From b36dee364e37c4b3295288d206f81dd6f1a03480 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 3 Aug 2018 11:44:40 -0400 Subject: filesystem: Remove unnecessary if conditions --- src/core/hle/service/filesystem/filesystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index e17d637e4..9b87e3484 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -59,7 +59,7 @@ ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const { std::string path(FileUtil::SanitizePath(path_)); auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); - if (path == "/" || path == "\\") { + if (path.empty()) { // TODO(DarkLordZach): Why do games call this and what should it do? Works as is but... return RESULT_SUCCESS; } -- cgit v1.2.3 From 3bf488ce520a81811bf6e949e2153aabf4b713ea Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 3 Aug 2018 11:46:30 -0400 Subject: vfs: Add VfsFilesystem interface and default implementation --- src/core/file_sys/vfs.cpp | 148 ++++++++++++++++++++++++++++++++++++++++++++++ src/core/file_sys/vfs.h | 66 ++++++++++++++++++++- 2 files changed, 211 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp index dae1c16ef..24e158962 100644 --- a/src/core/file_sys/vfs.cpp +++ b/src/core/file_sys/vfs.cpp @@ -4,12 +4,160 @@ #include #include +#include +#include "common/common_paths.h" #include "common/file_util.h" #include "common/logging/backend.h" #include "core/file_sys/vfs.h" namespace FileSys { +VfsFilesystem::VfsFilesystem(VirtualDir root_) : root(std::move(root_)) {} + +VfsFilesystem::~VfsFilesystem() = default; + +std::string VfsFilesystem::GetName() const { + return root->GetName(); +} + +bool VfsFilesystem::IsReadable() const { + return root->IsReadable(); +} + +bool VfsFilesystem::IsWritable() const { + return root->IsWritable(); +} + +VfsEntryType VfsFilesystem::GetEntryType(std::string_view path_) const { + const auto path = FileUtil::SanitizePath(path_); + if (root->GetFileRelative(path) != nullptr) + return VfsEntryType::File; + if (root->GetDirectoryRelative(path) != nullptr) + return VfsEntryType::Directory; + + return VfsEntryType::None; +} + +VirtualFile VfsFilesystem::OpenFile(std::string_view path_, Mode perms) { + const auto path = FileUtil::SanitizePath(path_); + return root->GetFileRelative(path); +} + +VirtualFile VfsFilesystem::CreateFile(std::string_view path_, Mode perms) { + const auto path = FileUtil::SanitizePath(path_); + return root->CreateFileRelative(path); +} + +VirtualFile VfsFilesystem::CopyFile(std::string_view old_path_, std::string_view new_path_) { + const auto old_path = FileUtil::SanitizePath(old_path_); + const auto new_path = FileUtil::SanitizePath(new_path_); + + // VfsDirectory impls are only required to implement copy across the current directory. + if (FileUtil::GetParentPath(old_path) == FileUtil::GetParentPath(new_path)) { + if (!root->Copy(FileUtil::GetFilename(old_path), FileUtil::GetFilename(new_path))) + return nullptr; + return OpenFile(new_path, Mode::ReadWrite); + } + + // Do it using RawCopy. Non-default impls are encouraged to optimize this. + const auto old_file = OpenFile(old_path, Mode::Read); + if (old_file == nullptr) + return nullptr; + auto new_file = OpenFile(new_path, Mode::Read); + if (new_file != nullptr) + return nullptr; + new_file = CreateFile(new_path, Mode::Write); + if (new_file == nullptr) + return nullptr; + if (!VfsRawCopy(old_file, new_file)) + return nullptr; + return new_file; +} + +VirtualFile VfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) { + const auto old_path = FileUtil::SanitizePath(old_path_); + const auto new_path = FileUtil::SanitizePath(new_path_); + + // Again, non-default impls are highly encouraged to provide a more optimized version of this. + auto out = CopyFile(old_path_, new_path_); + if (out == nullptr) + return nullptr; + if (DeleteFile(old_path)) + return out; + return nullptr; +} + +bool VfsFilesystem::DeleteFile(std::string_view path_) { + const auto path = FileUtil::SanitizePath(path_); + auto parent = OpenDirectory(FileUtil::GetParentPath(path), Mode::Write); + if (parent == nullptr) + return false; + return parent->DeleteFile(FileUtil::GetFilename(path)); +} + +VirtualDir VfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) { + const auto path = FileUtil::SanitizePath(path_); + return root->GetDirectoryRelative(path); +} + +VirtualDir VfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) { + const auto path = FileUtil::SanitizePath(path_); + return root->CreateDirectoryRelative(path); +} + +VirtualDir VfsFilesystem::CopyDirectory(std::string_view old_path_, std::string_view new_path_) { + const auto old_path = FileUtil::SanitizePath(old_path_); + const auto new_path = FileUtil::SanitizePath(new_path_); + + // Non-default impls are highly encouraged to provide a more optimized version of this. + auto old_dir = OpenDirectory(old_path, Mode::Read); + if (old_dir == nullptr) + return nullptr; + auto new_dir = OpenDirectory(new_path, Mode::Read); + if (new_dir != nullptr) + return nullptr; + new_dir = CreateDirectory(new_path, Mode::Write); + if (new_dir == nullptr) + return nullptr; + + for (const auto& file : old_dir->GetFiles()) { + const auto x = + CopyFile(old_path + DIR_SEP + file->GetName(), new_path + DIR_SEP + file->GetName()); + if (x == nullptr) + return nullptr; + } + + for (const auto& dir : old_dir->GetSubdirectories()) { + const auto x = + CopyDirectory(old_path + DIR_SEP + dir->GetName(), new_path + DIR_SEP + dir->GetName()); + if (x == nullptr) + return nullptr; + } + + return new_dir; +} + +VirtualDir VfsFilesystem::MoveDirectory(std::string_view old_path_, std::string_view new_path_) { + const auto old_path = FileUtil::SanitizePath(old_path_); + const auto new_path = FileUtil::SanitizePath(new_path_); + + // Non-default impls are highly encouraged to provide a more optimized version of this. + auto out = CopyDirectory(old_path_, new_path_); + if (out == nullptr) + return nullptr; + if (DeleteDirectory(old_path)) + return out; + return nullptr; +} + +bool VfsFilesystem::DeleteDirectory(std::string_view path_) { + const auto path = FileUtil::SanitizePath(path_); + auto parent = OpenDirectory(FileUtil::GetParentPath(path), Mode::Write); + if (parent == nullptr) + return false; + return parent->DeleteSubdirectoryRecursive(FileUtil::GetFilename(path)); +} + VfsFile::~VfsFile() = default; std::string VfsFile::GetExtension() const { diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h index fab9e2b45..9c7ef93b8 100644 --- a/src/core/file_sys/vfs.h +++ b/src/core/file_sys/vfs.h @@ -11,14 +11,74 @@ #include #include "boost/optional.hpp" #include "common/common_types.h" +#include "core/file_sys/mode.h" namespace FileSys { + +struct VfsFilesystem; struct VfsFile; struct VfsDirectory; -// Convenience typedefs to use VfsDirectory and VfsFile -using VirtualDir = std::shared_ptr; -using VirtualFile = std::shared_ptr; +// Convenience typedefs to use Vfs* interfaces +using VirtualFilesystem = std::shared_ptr; +using VirtualDir = std::shared_ptr; +using VirtualFile = std::shared_ptr; + +// An enumeration representing what can be at the end of a path in a VfsFilesystem +enum class VfsEntryType { + None, + File, + Directory, +}; + +// A class represnting an abstract filesystem. A default implementation given the root VirtualDir is +// provided for convenience, but if the Vfs implementation has any additional state or +// functionality, they will need to override. +struct VfsFilesystem : NonCopyable { + VfsFilesystem(VirtualDir root); + virtual ~VfsFilesystem(); + + // Gets the friendly name for the filesystem. + virtual std::string GetName() const; + + // Return whether or not the user has read permissions on this filesystem. + virtual bool IsReadable() const; + // Return whether or not the user has write permission on this filesystem. + virtual bool IsWritable() const; + + // Determine if the entry at path is non-existant, a file, or a directory. + virtual VfsEntryType GetEntryType(std::string_view path) const; + + // Opens the file with path relative to root. If it doesn't exist, returns nullptr. + virtual VirtualFile OpenFile(std::string_view path, Mode perms); + // Creates a new, empty file at path + virtual VirtualFile CreateFile(std::string_view path, Mode perms); + // Copies the file from old_path to new_path, returning the new file on success and nullptr on + // failure. + virtual VirtualFile CopyFile(std::string_view old_path, std::string_view new_path); + // Moves the file from old_path to new_path, returning the moved file on success and nullptr on + // failure. + virtual VirtualFile MoveFile(std::string_view old_path, std::string_view new_path); + // Deletes the file with path relative to root, returing true on success. + virtual bool DeleteFile(std::string_view path); + + // Opens the directory with path relative to root. If it doesn't exist, returns nullptr. + virtual VirtualDir OpenDirectory(std::string_view path, Mode perms); + // Creates a new, empty directory at path + virtual VirtualDir CreateDirectory(std::string_view path, Mode perms); + // Copies the directory from old_path to new_path, returning the new directory on success and + // nullptr on failure. + virtual VirtualDir CopyDirectory(std::string_view old_path, std::string_view new_path); + // Moves the directory from old_path to new_path, returning the moved directory on success and + // nullptr on failure. + virtual VirtualDir MoveDirectory(std::string_view old_path, std::string_view new_path); + // Deletes the directory with path relative to root, returing true on success. + virtual bool DeleteDirectory(std::string_view path); + +protected: + // Root directory in default implementation. + VirtualDir root; +}; // A class representing a file in an abstract filesystem. struct VfsFile : NonCopyable { -- cgit v1.2.3 From 3f82dad1e411130e309074a1547fb2104257f95d Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 3 Aug 2018 11:47:35 -0400 Subject: file_util: Add platform-specific slash option to SanitizePath --- src/common/file_util.cpp | 16 +++++++++++++--- src/common/file_util.h | 5 +++-- 2 files changed, 16 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index 7aeda737f..190cac6d9 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp @@ -884,11 +884,21 @@ std::string_view RemoveTrailingSlash(std::string_view path) { return path; } -std::string SanitizePath(std::string_view path_) { +std::string SanitizePath(std::string_view path_, bool with_platform_slashes) { std::string path(path_); - std::replace(path.begin(), path.end(), '\\', '/'); + char type1 = '\\'; + char type2 = '/'; + + if (with_platform_slashes) { +#ifdef _WIN32 + type1 = '/'; + type2 = '\\'; +#endif + } + + std::replace(path.begin(), path.end(), type1, type2); path.erase(std::unique(path.begin(), path.end(), - [](char c1, char c2) { return c1 == '/' && c2 == '/'; }), + [type2](char c1, char c2) { return c1 == type2 && c2 == type2; }), path.end()); return std::string(RemoveTrailingSlash(path)); } diff --git a/src/common/file_util.h b/src/common/file_util.h index d0987fb57..ca63d7466 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h @@ -182,8 +182,9 @@ std::vector SliceVector(const std::vector& vector, size_t first, size_t la return std::vector(vector.begin() + first, vector.begin() + first + last); } -// Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. -std::string SanitizePath(std::string_view path); +// Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\' +// if windows and with_platform_slashes is true. +std::string SanitizePath(std::string_view path, bool with_platform_slashes = false); // simple wrapper for cstdlib file functions to // hopefully will make error checking easier -- cgit v1.2.3 From 2de2ec25d6e8971809f98ebe36996c00e0f89f2d Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 3 Aug 2018 11:50:00 -0400 Subject: vfs: Add RealVfsFilesystem implementation --- src/core/file_sys/vfs_real.cpp | 327 +++++++++++++++++++++++++++++++---------- src/core/file_sys/vfs_real.h | 44 +++++- 2 files changed, 290 insertions(+), 81 deletions(-) (limited to 'src') diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index 82d54da4a..2923a8e6a 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp @@ -36,8 +36,164 @@ static std::string ModeFlagsToString(Mode mode) { return mode_str; } -RealVfsFile::RealVfsFile(const std::string& path_, Mode perms_) - : backing(path_, ModeFlagsToString(perms_).c_str()), path(path_), +RealVfsFilesystem::RealVfsFilesystem() : VfsFilesystem(nullptr) {} + +std::string RealVfsFilesystem::GetName() const { + return "Real"; +} + +bool RealVfsFilesystem::IsReadable() const { + return true; +} + +bool RealVfsFilesystem::IsWritable() const { + return true; +} + +VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const { + const auto path = FileUtil::SanitizePath(path_, true); + if (!FileUtil::Exists(path)) + return VfsEntryType::None; + if (FileUtil::IsDirectory(path)) + return VfsEntryType::Directory; + + return VfsEntryType::File; +} + +VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { + const auto path = FileUtil::SanitizePath(path_, true); + if (cache.find(path) != cache.end()) { + auto weak = cache[path]; + if (!weak.expired()) { + return std::shared_ptr(new RealVfsFile(*this, weak.lock(), path, perms)); + } + } + + if (!FileUtil::Exists(path) && (perms & Mode::WriteAppend) != 0) + FileUtil::CreateEmptyFile(path); + + auto backing = std::make_shared(path, ModeFlagsToString(perms).c_str()); + cache[path] = backing; + + // Cannot use make_shared as RealVfsFile constructor is private + return std::shared_ptr(new RealVfsFile(*this, backing, path, perms)); +} + +VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) { + const auto path = FileUtil::SanitizePath(path_, true); + if (!FileUtil::Exists(path) && !FileUtil::CreateEmptyFile(path)) + return nullptr; + return OpenFile(path, perms); +} + +VirtualFile RealVfsFilesystem::CopyFile(std::string_view old_path_, std::string_view new_path_) { + const auto old_path = FileUtil::SanitizePath(old_path_, true); + const auto new_path = FileUtil::SanitizePath(new_path_, true); + + if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) || + FileUtil::IsDirectory(old_path) || !FileUtil::Copy(old_path, new_path)) + return nullptr; + return OpenFile(new_path, Mode::ReadWrite); +} + +VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) { + const auto old_path = FileUtil::SanitizePath(old_path_, true); + const auto new_path = FileUtil::SanitizePath(new_path_, true); + + if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) || + FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path)) + return nullptr; + + if (cache.find(old_path) != cache.end()) { + auto cached = cache[old_path]; + if (!cached.expired()) { + auto file = cached.lock(); + file->Open(new_path, "r+b"); + cache.erase(old_path); + cache[new_path] = file; + } + } + return OpenFile(new_path, Mode::ReadWrite); +} + +bool RealVfsFilesystem::DeleteFile(std::string_view path_) { + const auto path = FileUtil::SanitizePath(path_, true); + if (cache.find(path) != cache.end()) { + if (!cache[path].expired()) + cache[path].lock()->Close(); + cache.erase(path); + } + return FileUtil::Delete(path); +} + +VirtualDir RealVfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) { + const auto path = FileUtil::SanitizePath(path_, true); + // Cannot use make_shared as RealVfsDirectory constructor is private + return std::shared_ptr(new RealVfsDirectory(*this, path, perms)); +} + +VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) { + const auto path = FileUtil::SanitizePath(path_, true); + if (!FileUtil::Exists(path) && !FileUtil::CreateDir(path)) + return nullptr; + // Cannot use make_shared as RealVfsDirectory constructor is private + return std::shared_ptr(new RealVfsDirectory(*this, path, perms)); +} + +VirtualDir RealVfsFilesystem::CopyDirectory(std::string_view old_path_, + std::string_view new_path_) { + const auto old_path = FileUtil::SanitizePath(old_path_, true); + const auto new_path = FileUtil::SanitizePath(new_path_, true); + if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) || + !FileUtil::IsDirectory(old_path)) + return nullptr; + FileUtil::CopyDir(old_path, new_path); + return OpenDirectory(new_path, Mode::ReadWrite); +} + +VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_, + std::string_view new_path_) { + const auto old_path = FileUtil::SanitizePath(old_path_, true); + const auto new_path = FileUtil::SanitizePath(new_path_, true); + if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) || + FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path)) + return nullptr; + + for (auto& kv : cache) { + // Path in cache starts with old_path + if (kv.first.rfind(old_path, 0) == 0) { + const auto file_old_path = FileUtil::SanitizePath(kv.first, true); + const auto file_new_path = + FileUtil::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()), true); + auto cached = cache[file_old_path]; + if (!cached.expired()) { + auto file = cached.lock(); + file->Open(file_new_path, "r+b"); + cache.erase(file_old_path); + cache[file_new_path] = file; + } + } + } + + return OpenDirectory(new_path, Mode::ReadWrite); +} + +bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) { + const auto path = FileUtil::SanitizePath(path_, true); + for (auto& kv : cache) { + // Path in cache starts with old_path + if (kv.first.rfind(path, 0) == 0) { + if (!cache[kv.first].expired()) + cache[kv.first].lock()->Close(); + cache.erase(kv.first); + } + } + return FileUtil::DeleteDirRecursively(path); +} + +RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::shared_ptr backing_, + const std::string& path_, Mode perms_) + : base(base_), backing(std::move(backing_)), path(path_), parent_path(FileUtil::GetParentPath(path_)), path_components(FileUtil::SplitPathComponents(path_)), parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)), @@ -48,15 +204,15 @@ std::string RealVfsFile::GetName() const { } size_t RealVfsFile::GetSize() const { - return backing.GetSize(); + return backing->GetSize(); } bool RealVfsFile::Resize(size_t new_size) { - return backing.Resize(new_size); + return backing->Resize(new_size); } std::shared_ptr RealVfsFile::GetContainingDirectory() const { - return std::make_shared(parent_path, perms); + return base.OpenDirectory(parent_path, perms); } bool RealVfsFile::IsWritable() const { @@ -68,62 +224,118 @@ bool RealVfsFile::IsReadable() const { } size_t RealVfsFile::Read(u8* data, size_t length, size_t offset) const { - if (!backing.Seek(offset, SEEK_SET)) + if (!backing->Seek(offset, SEEK_SET)) return 0; - return backing.ReadBytes(data, length); + return backing->ReadBytes(data, length); } size_t RealVfsFile::Write(const u8* data, size_t length, size_t offset) { - if (!backing.Seek(offset, SEEK_SET)) + if (!backing->Seek(offset, SEEK_SET)) return 0; - return backing.WriteBytes(data, length); + return backing->WriteBytes(data, length); } bool RealVfsFile::Rename(std::string_view name) { - std::string name_str(name.begin(), name.end()); - const auto out = FileUtil::Rename(GetName(), name_str); + return base.MoveFile(path, parent_path + DIR_SEP + std::string(name)) != nullptr; +} - path = (parent_path + DIR_SEP).append(name); - path_components = parent_components; - path_components.push_back(std::move(name_str)); - backing = FileUtil::IOFile(path, ModeFlagsToString(perms).c_str()); +bool RealVfsFile::Close() { + return backing->Close(); +} + +// TODO(DarkLordZach): MSVC would not let me combine the following two functions using 'if +// constexpr' because there is a compile error in the branch not used. + +template <> +std::vector RealVfsDirectory::IterateEntries() const { + if (perms == Mode::Append) + return {}; + + std::vector out; + FileUtil::ForeachDirectoryEntry( + nullptr, path, + [&out, this](u64* entries_out, const std::string& directory, const std::string& filename) { + const std::string full_path = directory + DIR_SEP + filename; + if (!FileUtil::IsDirectory(full_path)) + out.emplace_back(base.OpenFile(full_path, perms)); + return true; + }); return out; } -bool RealVfsFile::Close() { - return backing.Close(); +template <> +std::vector RealVfsDirectory::IterateEntries() const { + if (perms == Mode::Append) + return {}; + + std::vector out; + FileUtil::ForeachDirectoryEntry( + nullptr, path, + [&out, this](u64* entries_out, const std::string& directory, const std::string& filename) { + const std::string full_path = directory + DIR_SEP + filename; + if (FileUtil::IsDirectory(full_path)) + out.emplace_back(base.OpenDirectory(full_path, perms)); + return true; + }); + + return out; } -RealVfsDirectory::RealVfsDirectory(const std::string& path_, Mode perms_) - : path(FileUtil::RemoveTrailingSlash(path_)), parent_path(FileUtil::GetParentPath(path)), +RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string& path_, Mode perms_) + : base(base_), path(FileUtil::RemoveTrailingSlash(path_)), + parent_path(FileUtil::GetParentPath(path)), path_components(FileUtil::SplitPathComponents(path)), parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)), perms(perms_) { if (!FileUtil::Exists(path) && perms & Mode::WriteAppend) FileUtil::CreateDir(path); +} - if (perms == Mode::Append) - return; +std::shared_ptr RealVfsDirectory::GetFileRelative(std::string_view path) const { + const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path)); + if (!FileUtil::Exists(full_path)) + return nullptr; + return base.OpenFile(full_path, perms); +} - FileUtil::ForeachDirectoryEntry( - nullptr, path, - [this](u64* entries_out, const std::string& directory, const std::string& filename) { - std::string full_path = directory + DIR_SEP + filename; - if (FileUtil::IsDirectory(full_path)) - subdirectories.emplace_back(std::make_shared(full_path, perms)); - else - files.emplace_back(std::make_shared(full_path, perms)); - return true; - }); +std::shared_ptr RealVfsDirectory::GetDirectoryRelative(std::string_view path) const { + const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path)); + if (!FileUtil::Exists(full_path)) + return nullptr; + return base.OpenDirectory(full_path, perms); +} + +std::shared_ptr RealVfsDirectory::GetFile(std::string_view name) const { + return GetFileRelative(name); +} + +std::shared_ptr RealVfsDirectory::GetSubdirectory(std::string_view name) const { + return GetDirectoryRelative(name); +} + +std::shared_ptr RealVfsDirectory::CreateFileRelative(std::string_view path) { + const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path)); + return base.CreateFile(full_path, perms); +} + +std::shared_ptr RealVfsDirectory::CreateDirectoryRelative(std::string_view path) { + const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path)); + auto parent = std::string(FileUtil::GetParentPath(full_path)); + return base.CreateDirectory(full_path, perms); +} + +bool RealVfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) { + auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(name)); + return base.DeleteDirectory(full_path); } std::vector> RealVfsDirectory::GetFiles() const { - return files; + return IterateEntries(); } std::vector> RealVfsDirectory::GetSubdirectories() const { - return subdirectories; + return IterateEntries(); } bool RealVfsDirectory::IsWritable() const { @@ -142,57 +354,32 @@ std::shared_ptr RealVfsDirectory::GetParentDirectory() const { if (path_components.size() <= 1) return nullptr; - return std::make_shared(parent_path, perms); + return base.OpenDirectory(parent_path, perms); } std::shared_ptr RealVfsDirectory::CreateSubdirectory(std::string_view name) { const std::string subdir_path = (path + DIR_SEP).append(name); - - if (!FileUtil::CreateDir(subdir_path)) { - return nullptr; - } - - subdirectories.emplace_back(std::make_shared(subdir_path, perms)); - return subdirectories.back(); + return base.CreateDirectory(subdir_path, perms); } std::shared_ptr RealVfsDirectory::CreateFile(std::string_view name) { const std::string file_path = (path + DIR_SEP).append(name); - - if (!FileUtil::CreateEmptyFile(file_path)) { - return nullptr; - } - - files.emplace_back(std::make_shared(file_path, perms)); - return files.back(); + return base.CreateFile(file_path, perms); } bool RealVfsDirectory::DeleteSubdirectory(std::string_view name) { const std::string subdir_path = (path + DIR_SEP).append(name); - - return FileUtil::DeleteDirRecursively(subdir_path); + return base.DeleteDirectory(subdir_path); } bool RealVfsDirectory::DeleteFile(std::string_view name) { - const auto file = GetFile(name); - - if (file == nullptr) { - return false; - } - - files.erase(std::find(files.begin(), files.end(), file)); - - auto real_file = std::static_pointer_cast(file); - real_file->Close(); - const std::string file_path = (path + DIR_SEP).append(name); - return FileUtil::Delete(file_path); + return base.DeleteFile(file_path); } bool RealVfsDirectory::Rename(std::string_view name) { const std::string new_name = (parent_path + DIR_SEP).append(name); - - return FileUtil::Rename(path, new_name); + return base.MoveFile(path, new_name) != nullptr; } std::string RealVfsDirectory::GetFullPath() const { @@ -202,16 +389,6 @@ std::string RealVfsDirectory::GetFullPath() const { } bool RealVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { - const auto iter = std::find(files.begin(), files.end(), file); - if (iter == files.end()) - return false; - - const std::ptrdiff_t offset = std::distance(files.begin(), iter); - files[offset] = files.back(); - files.pop_back(); - - subdirectories.emplace_back(std::move(dir)); - - return true; + return false; } } // namespace FileSys diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h index 243d58576..dbb381a2a 100644 --- a/src/core/file_sys/vfs_real.h +++ b/src/core/file_sys/vfs_real.h @@ -6,18 +6,45 @@ #include +#include #include "common/file_util.h" #include "core/file_sys/mode.h" #include "core/file_sys/vfs.h" namespace FileSys { +class RealVfsFilesystem : public VfsFilesystem { +public: + RealVfsFilesystem(); + + std::string GetName() const override; + bool IsReadable() const override; + bool IsWritable() const override; + VfsEntryType GetEntryType(std::string_view path) const override; + VirtualFile OpenFile(std::string_view path, Mode perms = Mode::Read) override; + VirtualFile CreateFile(std::string_view path, Mode perms = Mode::ReadWrite) override; + VirtualFile CopyFile(std::string_view old_path, std::string_view new_path) override; + VirtualFile MoveFile(std::string_view old_path, std::string_view new_path) override; + bool DeleteFile(std::string_view path) override; + VirtualDir OpenDirectory(std::string_view path, Mode perms = Mode::Read) override; + VirtualDir CreateDirectory(std::string_view path, Mode perms = Mode::ReadWrite) override; + VirtualDir CopyDirectory(std::string_view old_path, std::string_view new_path) override; + VirtualDir MoveDirectory(std::string_view old_path, std::string_view new_path) override; + bool DeleteDirectory(std::string_view path) override; + +private: + boost::container::flat_map> cache; +}; + // An implmentation of VfsFile that represents a file on the user's computer. -struct RealVfsFile : public VfsFile { - friend struct RealVfsDirectory; +class RealVfsFile : public VfsFile { + friend class RealVfsDirectory; + friend class RealVfsFilesystem; - RealVfsFile(const std::string& name, Mode perms = Mode::Read); + RealVfsFile(RealVfsFilesystem& base, std::shared_ptr backing, + const std::string& path, Mode perms = Mode::Read); +public: std::string GetName() const override; size_t GetSize() const override; bool Resize(size_t new_size) override; @@ -31,7 +58,8 @@ struct RealVfsFile : public VfsFile { private: bool Close(); - FileUtil::IOFile backing; + RealVfsFilesystem& base; + std::shared_ptr backing; std::string path; std::string parent_path; std::vector path_components; @@ -40,9 +68,12 @@ private: }; // An implementation of VfsDirectory that represents a directory on the user's computer. -struct RealVfsDirectory : public VfsDirectory { - RealVfsDirectory(const std::string& path, Mode perms = Mode::Read); +class RealVfsDirectory : public VfsDirectory { + friend class RealVfsFilesystem; + + RealVfsDirectory(RealVfsFilesystem& base, const std::string& path, Mode perms = Mode::Read); +public: std::vector> GetFiles() const override; std::vector> GetSubdirectories() const override; bool IsWritable() const override; @@ -60,6 +91,7 @@ protected: bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; private: + RealVfsFilesystem& base; std::string path; std::string parent_path; std::vector path_components; -- cgit v1.2.3 From aaa8fdea527d635e6503a1411a06938325cba216 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 3 Aug 2018 11:50:27 -0400 Subject: vfs: Add unreachable assert to file permissions converter --- src/core/file_sys/vfs_real.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index 2923a8e6a..21ea35aaf 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp @@ -6,7 +6,7 @@ #include #include #include - +#include "common/assert.h" #include "common/common_paths.h" #include "common/logging/log.h" #include "core/file_sys/vfs_real.h" @@ -29,6 +29,8 @@ static std::string ModeFlagsToString(Mode mode) { mode_str = "a"; else if (mode & Mode::Write) mode_str = "w"; + else + UNREACHABLE_MSG("Invalid file open mode: {:02X}", static_cast(mode)); } mode_str += "b"; -- cgit v1.2.3 From 4b471f0554146463f3b82eed14ff3922a5584e9f Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 3 Aug 2018 11:51:48 -0400 Subject: core: Port core to VfsFilesystem for file access --- src/core/core.cpp | 8 ++++++-- src/core/core.h | 12 ++++++++++++ src/core/hle/service/filesystem/filesystem.cpp | 14 +++++++------- src/core/hle/service/filesystem/filesystem.h | 2 +- src/core/hle/service/service.cpp | 4 ++-- src/core/hle/service/service.h | 7 ++++++- src/yuzu/game_list.cpp | 7 ++++--- src/yuzu/game_list.h | 3 ++- src/yuzu/game_list_p.h | 3 ++- src/yuzu/main.cpp | 10 ++++++---- src/yuzu/main.h | 3 +++ src/yuzu_cmd/yuzu.cpp | 1 + 12 files changed, 52 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/core/core.cpp b/src/core/core.cpp index 085ba68d0..69c45c026 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -89,7 +89,7 @@ System::ResultStatus System::SingleStep() { } System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& filepath) { - app_loader = Loader::GetLoader(std::make_shared(filepath)); + app_loader = Loader::GetLoader(virtual_filesystem->OpenFile(filepath, FileSys::Mode::Read)); if (!app_loader) { LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); @@ -174,6 +174,10 @@ System::ResultStatus System::Init(EmuWindow& emu_window) { CoreTiming::Init(); + // Create a default fs if one doesn't already exist. + if (virtual_filesystem == nullptr) + virtual_filesystem = std::make_shared(); + current_process = Kernel::Process::Create("main"); cpu_barrier = std::make_shared(); @@ -186,7 +190,7 @@ System::ResultStatus System::Init(EmuWindow& emu_window) { service_manager = std::make_shared(); Kernel::Init(); - Service::Init(service_manager); + Service::Init(service_manager, virtual_filesystem); GDBStub::Init(); renderer = VideoCore::CreateRenderer(emu_window); diff --git a/src/core/core.h b/src/core/core.h index c8ca4b247..7cf7ea4e1 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -17,6 +17,8 @@ #include "core/memory.h" #include "core/perf_stats.h" #include "core/telemetry_session.h" +#include "file_sys/vfs_real.h" +#include "hle/service/filesystem/filesystem.h" #include "video_core/debug_utils/debug_utils.h" #include "video_core/gpu.h" @@ -211,6 +213,14 @@ public: return debug_context; } + void SetFilesystem(FileSys::VirtualFilesystem vfs) { + virtual_filesystem = std::move(vfs); + } + + FileSys::VirtualFilesystem GetFilesystem() const { + return virtual_filesystem; + } + private: System(); @@ -225,6 +235,8 @@ private: */ ResultStatus Init(EmuWindow& emu_window); + /// RealVfsFilesystem instance + FileSys::VirtualFilesystem virtual_filesystem; /// AppLoader used to load the current executing application std::unique_ptr app_loader; std::unique_ptr renderer; diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 9b87e3484..5e416cde2 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -281,15 +281,15 @@ ResultVal OpenSDMC() { return sdmc_factory->Open(); } -void RegisterFileSystems() { +void RegisterFileSystems(const FileSys::VirtualFilesystem& vfs) { romfs_factory = nullptr; save_data_factory = nullptr; sdmc_factory = nullptr; - auto nand_directory = std::make_shared( - FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), FileSys::Mode::ReadWrite); - auto sd_directory = std::make_shared( - FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), FileSys::Mode::ReadWrite); + auto nand_directory = vfs->OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), + FileSys::Mode::ReadWrite); + auto sd_directory = vfs->OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), + FileSys::Mode::ReadWrite); auto savedata = std::make_unique(std::move(nand_directory)); save_data_factory = std::move(savedata); @@ -298,8 +298,8 @@ void RegisterFileSystems() { sdmc_factory = std::move(sdcard); } -void InstallInterfaces(SM::ServiceManager& service_manager) { - RegisterFileSystems(); +void InstallInterfaces(SM::ServiceManager& service_manager, const FileSys::VirtualFilesystem& vfs) { + RegisterFileSystems(vfs); std::make_shared()->InstallAsService(service_manager); std::make_shared()->InstallAsService(service_manager); std::make_shared()->InstallAsService(service_manager); diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index d4483daa5..462c13f20 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -36,7 +36,7 @@ ResultVal OpenSDMC(); // ResultVal> OpenBIS(); /// Registers all Filesystem services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager); +void InstallInterfaces(SM::ServiceManager& service_manager, const FileSys::VirtualFilesystem& vfs); // A class that wraps a VfsDirectory with methods that return ResultVal and ResultCode instead of // pointers and booleans. This makes using a VfsDirectory with switch services much easier and diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 6f286ea74..11951adaf 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -198,7 +198,7 @@ void AddNamedPort(std::string name, SharedPtr port) { } /// Initialize ServiceManager -void Init(std::shared_ptr& sm) { +void Init(std::shared_ptr& sm, const FileSys::VirtualFilesystem& rfs) { // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it // here and pass it into the respective InstallInterfaces functions. auto nv_flinger = std::make_shared(); @@ -221,7 +221,7 @@ void Init(std::shared_ptr& sm) { EUPLD::InstallInterfaces(*sm); Fatal::InstallInterfaces(*sm); FGM::InstallInterfaces(*sm); - FileSystem::InstallInterfaces(*sm); + FileSystem::InstallInterfaces(*sm, rfs); Friend::InstallInterfaces(*sm); GRC::InstallInterfaces(*sm); HID::InstallInterfaces(*sm); diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 046c5e18d..8a294c0f2 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -22,6 +22,10 @@ class ServerSession; class HLERequestContext; } // namespace Kernel +namespace FileSys { +struct VfsFilesystem; +} + namespace Service { namespace SM { @@ -177,7 +181,8 @@ private: }; /// Initialize ServiceManager -void Init(std::shared_ptr& sm); +void Init(std::shared_ptr& sm, + const std::shared_ptr& vfs); /// Shutdown ServiceManager void Shutdown(); diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 5f47f5a2b..e150a0684 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -197,7 +197,8 @@ void GameList::onFilterCloseClicked() { main_window->filterBarSetChecked(false); } -GameList::GameList(GMainWindow* parent) : QWidget{parent} { +GameList::GameList(FileSys::VirtualFilesystem vfs, GMainWindow* parent) + : QWidget{parent}, vfs(std::move(vfs)) { watcher = new QFileSystemWatcher(this); connect(watcher, &QFileSystemWatcher::directoryChanged, this, &GameList::RefreshGameDirectory); @@ -341,7 +342,7 @@ void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) { emit ShouldCancelWorker(); - GameListWorker* worker = new GameListWorker(dir_path, deep_scan); + GameListWorker* worker = new GameListWorker(vfs, dir_path, deep_scan); connect(worker, &GameListWorker::EntryReady, this, &GameList::AddEntry, Qt::QueuedConnection); connect(worker, &GameListWorker::Finished, this, &GameList::DonePopulating, @@ -436,7 +437,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign if (!is_dir && (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) { std::unique_ptr loader = - Loader::GetLoader(std::make_shared(physical_name)); + Loader::GetLoader(vfs->OpenFile(physical_name, FileSys::Mode::Read)); if (!loader || ((loader->GetFileType() == Loader::FileType::Unknown || loader->GetFileType() == Loader::FileType::Error) && !UISettings::values.show_unknown)) diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 3bc14f07f..afe624b32 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h @@ -59,7 +59,7 @@ public: QToolButton* button_filter_close = nullptr; }; - explicit GameList(GMainWindow* parent = nullptr); + explicit GameList(FileSys::VirtualFilesystem vfs, GMainWindow* parent = nullptr); ~GameList() override; void clearFilter(); @@ -90,6 +90,7 @@ private: void PopupContextMenu(const QPoint& menu_location); void RefreshGameDirectory(); + FileSys::VirtualFilesystem vfs; SearchField* search_field; GMainWindow* main_window = nullptr; QVBoxLayout* layout = nullptr; diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index a22025e67..49a3f6181 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h @@ -139,7 +139,7 @@ class GameListWorker : public QObject, public QRunnable { Q_OBJECT public: - GameListWorker(QString dir_path, bool deep_scan) + GameListWorker(FileSys::VirtualFilesystem vfs, QString dir_path, bool deep_scan) : dir_path(std::move(dir_path)), deep_scan(deep_scan) {} public slots: @@ -163,6 +163,7 @@ signals: void Finished(QStringList watch_list); private: + FileSys::VirtualFilesystem vfs; QStringList watch_list; QString dir_path; bool deep_scan; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index a6241e63e..f7812a392 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -24,6 +24,7 @@ #include "common/string_util.h" #include "core/core.h" #include "core/crypto/key_manager.h" +#include "core/file_sys/vfs_real.h" #include "core/gdbstub/gdbstub.h" #include "core/loader/loader.h" #include "core/settings.h" @@ -81,9 +82,9 @@ static void ShowCalloutMessage(const QString& message, CalloutFlag flag) { void GMainWindow::ShowCallouts() {} -const int GMainWindow::max_recent_files_item; - -GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) { +GMainWindow::GMainWindow() + : config(new Config()), emu_thread(nullptr), + vfs(std::make_shared()) { debug_context = Tegra::DebugContext::Construct(); @@ -132,7 +133,7 @@ void GMainWindow::InitializeWidgets() { render_window = new GRenderWindow(this, emu_thread.get()); render_window->hide(); - game_list = new GameList(this); + game_list = new GameList(vfs, this); ui.horizontalLayout->addWidget(game_list); // Create status bar @@ -406,6 +407,7 @@ bool GMainWindow::LoadROM(const QString& filename) { } Core::System& system{Core::System::GetInstance()}; + system.SetFilesystem(vfs); system.SetGPUDebugContext(debug_context); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 6e335b8f8..74487c58c 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -161,6 +161,9 @@ private: bool emulation_running = false; std::unique_ptr emu_thread; + // FS + FileSys::VirtualFilesystem vfs; + // Debugger panes ProfilerWidget* profilerWidget; MicroProfileDialog* microProfileDialog; diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index d637dbd0c..0605c92e3 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -161,6 +161,7 @@ int main(int argc, char** argv) { } Core::System& system{Core::System::GetInstance()}; + system.SetFilesystem(std::make_shared()); SCOPE_EXIT({ system.Shutdown(); }); -- cgit v1.2.3 From 52a2e42cb93d7ebfd329aafb04b8bd0aaa67e19e Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 3 Aug 2018 11:52:12 -0400 Subject: file_sys: Add missing include in savedata_factory --- src/core/file_sys/savedata_factory.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h index e3a578c0f..f3cf50d5a 100644 --- a/src/core/file_sys/savedata_factory.h +++ b/src/core/file_sys/savedata_factory.h @@ -7,6 +7,7 @@ #include #include #include "common/common_types.h" +#include "common/swap.h" #include "core/hle/result.h" namespace FileSys { -- cgit v1.2.3 From 656e97df16944dd997e18a58829001008760bf01 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 3 Aug 2018 11:52:42 -0400 Subject: vfs: Use RealVfsFilesystem for fs-operations in RealVfsDirectory --- src/core/file_sys/vfs_real.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h index dbb381a2a..8a1e79ef6 100644 --- a/src/core/file_sys/vfs_real.h +++ b/src/core/file_sys/vfs_real.h @@ -74,6 +74,13 @@ class RealVfsDirectory : public VfsDirectory { RealVfsDirectory(RealVfsFilesystem& base, const std::string& path, Mode perms = Mode::Read); public: + std::shared_ptr GetFileRelative(std::string_view path) const override; + std::shared_ptr GetDirectoryRelative(std::string_view path) const override; + std::shared_ptr GetFile(std::string_view name) const override; + std::shared_ptr GetSubdirectory(std::string_view name) const override; + std::shared_ptr CreateFileRelative(std::string_view path) override; + std::shared_ptr CreateDirectoryRelative(std::string_view path) override; + bool DeleteSubdirectoryRecursive(std::string_view name) override; std::vector> GetFiles() const override; std::vector> GetSubdirectories() const override; bool IsWritable() const override; @@ -91,14 +98,15 @@ protected: bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; private: + template + std::vector> IterateEntries() const; + RealVfsFilesystem& base; std::string path; std::string parent_path; std::vector path_components; std::vector parent_components; Mode perms; - std::vector> files; - std::vector> subdirectories; }; } // namespace FileSys -- cgit v1.2.3 From dad2ae1ee01b42bb6bb8a903c856712fc2bffa37 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 3 Aug 2018 11:56:44 -0400 Subject: loader: Remove unused IdentifyFile overload --- src/core/loader/loader.cpp | 4 ---- src/core/loader/loader.h | 8 -------- 2 files changed, 12 deletions(-) (limited to 'src') diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 0781fb8c1..a288654df 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -43,10 +43,6 @@ FileType IdentifyFile(FileSys::VirtualFile file) { return FileType::Unknown; } -FileType IdentifyFile(const std::string& file_name) { - return IdentifyFile(std::make_shared(file_name)); -} - FileType GuessFromFilename(const std::string& name) { if (name == "main") return FileType::DeconstructedRomDirectory; diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 7bd0adedb..6a9e5a68b 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -42,14 +42,6 @@ enum class FileType { */ FileType IdentifyFile(FileSys::VirtualFile file); -/** - * Identifies the type of a bootable file based on the magic value in its header. - * @param file_name path to file - * @return FileType of file. Note: this will return FileType::Unknown if it is unable to determine - * a filetype, and will never return FileType::Error. - */ -FileType IdentifyFile(const std::string& file_name); - /** * Guess the type of a bootable file from its name * @param name String name of bootable file -- cgit v1.2.3 From 2b6128fe0b8788318a4bbe1fc55ea14aed2981e4 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Mon, 6 Aug 2018 23:21:37 -0400 Subject: file_util: Use enum instead of bool for specifing path behavior --- src/common/file_util.cpp | 8 ++++---- src/common/file_util.h | 7 +++++-- src/core/file_sys/vfs_real.cpp | 44 ++++++++++++++++++++++++++---------------- src/yuzu/game_list_p.h | 2 +- 4 files changed, 37 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index 190cac6d9..3ce590062 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp @@ -884,12 +884,12 @@ std::string_view RemoveTrailingSlash(std::string_view path) { return path; } -std::string SanitizePath(std::string_view path_, bool with_platform_slashes) { +std::string SanitizePath(std::string_view path_, DirectorySeparator directory_separator) { std::string path(path_); - char type1 = '\\'; - char type2 = '/'; + char type1 = directory_separator == DirectorySeparator::BackwardSlash ? '/' : '\\'; + char type2 = directory_separator == DirectorySeparator::BackwardSlash ? '\\' : '/'; - if (with_platform_slashes) { + if (directory_separator == DirectorySeparator::PlatformDefault) { #ifdef _WIN32 type1 = '/'; type2 = '\\'; diff --git a/src/common/file_util.h b/src/common/file_util.h index ca63d7466..2711872ae 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h @@ -182,9 +182,12 @@ std::vector SliceVector(const std::vector& vector, size_t first, size_t la return std::vector(vector.begin() + first, vector.begin() + first + last); } +enum class DirectorySeparator { ForwardSlash, BackwardSlash, PlatformDefault }; + // Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\' -// if windows and with_platform_slashes is true. -std::string SanitizePath(std::string_view path, bool with_platform_slashes = false); +// depending if directory_separator is BackwardSlash or PlatformDefault and running on windows +std::string SanitizePath(std::string_view path, + DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash); // simple wrapper for cstdlib file functions to // hopefully will make error checking easier diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index 21ea35aaf..1b5919737 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp @@ -53,7 +53,7 @@ bool RealVfsFilesystem::IsWritable() const { } VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const { - const auto path = FileUtil::SanitizePath(path_, true); + const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); if (!FileUtil::Exists(path)) return VfsEntryType::None; if (FileUtil::IsDirectory(path)) @@ -63,7 +63,7 @@ VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const { } VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { - const auto path = FileUtil::SanitizePath(path_, true); + const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); if (cache.find(path) != cache.end()) { auto weak = cache[path]; if (!weak.expired()) { @@ -82,15 +82,17 @@ VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { } VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) { - const auto path = FileUtil::SanitizePath(path_, true); + const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); if (!FileUtil::Exists(path) && !FileUtil::CreateEmptyFile(path)) return nullptr; return OpenFile(path, perms); } VirtualFile RealVfsFilesystem::CopyFile(std::string_view old_path_, std::string_view new_path_) { - const auto old_path = FileUtil::SanitizePath(old_path_, true); - const auto new_path = FileUtil::SanitizePath(new_path_, true); + const auto old_path = + FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault); + const auto new_path = + FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault); if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) || FileUtil::IsDirectory(old_path) || !FileUtil::Copy(old_path, new_path)) @@ -99,8 +101,10 @@ VirtualFile RealVfsFilesystem::CopyFile(std::string_view old_path_, std::string_ } VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) { - const auto old_path = FileUtil::SanitizePath(old_path_, true); - const auto new_path = FileUtil::SanitizePath(new_path_, true); + const auto old_path = + FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault); + const auto new_path = + FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault); if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) || FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path)) @@ -119,7 +123,7 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_ } bool RealVfsFilesystem::DeleteFile(std::string_view path_) { - const auto path = FileUtil::SanitizePath(path_, true); + const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); if (cache.find(path) != cache.end()) { if (!cache[path].expired()) cache[path].lock()->Close(); @@ -129,13 +133,13 @@ bool RealVfsFilesystem::DeleteFile(std::string_view path_) { } VirtualDir RealVfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) { - const auto path = FileUtil::SanitizePath(path_, true); + const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); // Cannot use make_shared as RealVfsDirectory constructor is private return std::shared_ptr(new RealVfsDirectory(*this, path, perms)); } VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) { - const auto path = FileUtil::SanitizePath(path_, true); + const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); if (!FileUtil::Exists(path) && !FileUtil::CreateDir(path)) return nullptr; // Cannot use make_shared as RealVfsDirectory constructor is private @@ -144,8 +148,10 @@ VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms VirtualDir RealVfsFilesystem::CopyDirectory(std::string_view old_path_, std::string_view new_path_) { - const auto old_path = FileUtil::SanitizePath(old_path_, true); - const auto new_path = FileUtil::SanitizePath(new_path_, true); + const auto old_path = + FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault); + const auto new_path = + FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault); if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) || !FileUtil::IsDirectory(old_path)) return nullptr; @@ -155,8 +161,10 @@ VirtualDir RealVfsFilesystem::CopyDirectory(std::string_view old_path_, VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_, std::string_view new_path_) { - const auto old_path = FileUtil::SanitizePath(old_path_, true); - const auto new_path = FileUtil::SanitizePath(new_path_, true); + const auto old_path = + FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault); + const auto new_path = + FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault); if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) || FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path)) return nullptr; @@ -164,9 +172,11 @@ VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_, for (auto& kv : cache) { // Path in cache starts with old_path if (kv.first.rfind(old_path, 0) == 0) { - const auto file_old_path = FileUtil::SanitizePath(kv.first, true); + const auto file_old_path = + FileUtil::SanitizePath(kv.first, FileUtil::DirectorySeparator::PlatformDefault); const auto file_new_path = - FileUtil::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()), true); + FileUtil::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()), + FileUtil::DirectorySeparator::PlatformDefault); auto cached = cache[file_old_path]; if (!cached.expired()) { auto file = cached.lock(); @@ -181,7 +191,7 @@ VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_, } bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) { - const auto path = FileUtil::SanitizePath(path_, true); + const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); for (auto& kv : cache) { // Path in cache starts with old_path if (kv.first.rfind(path, 0) == 0) { diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index 49a3f6181..114a0fc7f 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h @@ -140,7 +140,7 @@ class GameListWorker : public QObject, public QRunnable { public: GameListWorker(FileSys::VirtualFilesystem vfs, QString dir_path, bool deep_scan) - : dir_path(std::move(dir_path)), deep_scan(deep_scan) {} + : vfs(std::move(vfs)), dir_path(std::move(dir_path)), deep_scan(deep_scan) {} public slots: /// Starts the processing of directory tree information. -- cgit v1.2.3 From 94cf327e776eff934052847346d8415d584b369b Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Wed, 8 Aug 2018 14:34:06 -0400 Subject: vfs: Fix typo in VfsFilesystem docs --- src/core/file_sys/vfs.h | 2 +- src/yuzu/game_list.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h index 9c7ef93b8..bf16e7286 100644 --- a/src/core/file_sys/vfs.h +++ b/src/core/file_sys/vfs.h @@ -31,7 +31,7 @@ enum class VfsEntryType { Directory, }; -// A class represnting an abstract filesystem. A default implementation given the root VirtualDir is +// A class representing an abstract filesystem. A default implementation given the root VirtualDir is // provided for convenience, but if the Vfs implementation has any additional state or // functionality, they will need to override. struct VfsFilesystem : NonCopyable { diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index e150a0684..1c738d2a4 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -15,6 +15,7 @@ #include "common/string_util.h" #include "core/file_sys/content_archive.h" #include "core/file_sys/control_metadata.h" +#include "core/file_sys/romfs.h" #include "core/file_sys/vfs_real.h" #include "core/loader/loader.h" #include "game_list.h" @@ -415,8 +416,8 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign bool is_dir = FileUtil::IsDirectory(physical_name); QFileInfo file_info(physical_name.c_str()); if (!is_dir && file_info.suffix().toStdString() == "nca") { - auto nca = std::make_shared( - std::make_shared(physical_name)); + auto nca = + std::make_shared(vfs->OpenFile(physical_name, FileSys::Mode::Read)); if (nca->GetType() == FileSys::NCAContentType::Control) nca_control_map.insert_or_assign(nca->GetTitleId(), nca); } @@ -460,7 +461,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign // Use from metadata pool. if (nca_control_map.find(program_id) != nca_control_map.end()) { const auto nca = nca_control_map[program_id]; - const auto control_dir = nca->GetSubdirectories()[0]; + const auto control_dir = FileSys::ExtractRomFS(nca->GetRomFS()); const auto nacp_file = control_dir->GetFile("control.nacp"); FileSys::NACP nacp(nacp_file); -- cgit v1.2.3 From 668458525ede125509ee27388221247b639f4676 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Wed, 8 Aug 2018 21:44:59 -0400 Subject: vfs: Fix documentation --- src/core/file_sys/vfs.h | 4 ++-- src/yuzu/main.cpp | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h index bf16e7286..141a053ce 100644 --- a/src/core/file_sys/vfs.h +++ b/src/core/file_sys/vfs.h @@ -31,8 +31,8 @@ enum class VfsEntryType { Directory, }; -// A class representing an abstract filesystem. A default implementation given the root VirtualDir is -// provided for convenience, but if the Vfs implementation has any additional state or +// A class representing an abstract filesystem. A default implementation given the root VirtualDir +// is provided for convenience, but if the Vfs implementation has any additional state or // functionality, they will need to override. struct VfsFilesystem : NonCopyable { VfsFilesystem(VirtualDir root); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index f7812a392..67e3c6549 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -82,6 +82,8 @@ static void ShowCalloutMessage(const QString& message, CalloutFlag flag) { void GMainWindow::ShowCallouts() {} +const int GMainWindow::max_recent_files_item; + GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr), vfs(std::make_shared()) { -- cgit v1.2.3