mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	vfs: Add VfsFilesystem interface and default implementation
This commit is contained in:
		
							parent
							
								
									b36dee364e
								
							
						
					
					
						commit
						3bf488ce52
					
				@ -4,12 +4,160 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <algorithm>
 | 
					#include <algorithm>
 | 
				
			||||||
#include <numeric>
 | 
					#include <numeric>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include "common/common_paths.h"
 | 
				
			||||||
#include "common/file_util.h"
 | 
					#include "common/file_util.h"
 | 
				
			||||||
#include "common/logging/backend.h"
 | 
					#include "common/logging/backend.h"
 | 
				
			||||||
#include "core/file_sys/vfs.h"
 | 
					#include "core/file_sys/vfs.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace FileSys {
 | 
					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;
 | 
					VfsFile::~VfsFile() = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
std::string VfsFile::GetExtension() const {
 | 
					std::string VfsFile::GetExtension() const {
 | 
				
			||||||
 | 
				
			|||||||
@ -11,14 +11,74 @@
 | 
				
			|||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
#include "boost/optional.hpp"
 | 
					#include "boost/optional.hpp"
 | 
				
			||||||
#include "common/common_types.h"
 | 
					#include "common/common_types.h"
 | 
				
			||||||
 | 
					#include "core/file_sys/mode.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace FileSys {
 | 
					namespace FileSys {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct VfsFilesystem;
 | 
				
			||||||
struct VfsFile;
 | 
					struct VfsFile;
 | 
				
			||||||
struct VfsDirectory;
 | 
					struct VfsDirectory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Convenience typedefs to use VfsDirectory and VfsFile
 | 
					// Convenience typedefs to use Vfs* interfaces
 | 
				
			||||||
using VirtualDir = std::shared_ptr<FileSys::VfsDirectory>;
 | 
					using VirtualFilesystem = std::shared_ptr<VfsFilesystem>;
 | 
				
			||||||
using VirtualFile = std::shared_ptr<FileSys::VfsFile>;
 | 
					using VirtualDir = std::shared_ptr<VfsDirectory>;
 | 
				
			||||||
 | 
					using VirtualFile = std::shared_ptr<VfsFile>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 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.
 | 
					// A class representing a file in an abstract filesystem.
 | 
				
			||||||
struct VfsFile : NonCopyable {
 | 
					struct VfsFile : NonCopyable {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user