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 a new issue