Compare commits

...

11 Commits

Author SHA1 Message Date
Zach Hilman
73b641e182 Merge ed92a69efc into 838724c588 2018-06-24 00:58:04 +00:00
Zach Hilman
ed92a69efc Use experimental/filesystem or filesystem depending on compiler 2018-06-23 17:38:23 -04:00
Zach Hilman
ecceac8954 Remove double const 2018-06-23 16:19:11 -04:00
Zach Hilman
008337c585 Major refactor 2018-06-23 16:11:38 -04:00
Zach Hilman
994f0de11d Fix import paths 2018-06-21 11:00:50 -04:00
Zach Hilman
28a5b3674c More changes 2018-06-20 19:28:48 -04:00
Zach Hilman
1cc6419524 Finished OffsetVfsFile 2018-06-19 21:52:41 -04:00
Zach Hilman
a2fb1a04d5 Finish RealVfsFile and RealVfsDirectory 2018-06-18 11:37:39 -04:00
Zach Hilman
4dff72a6e1 Implement RealVfsFile (computer fs backend) 2018-06-17 23:05:06 -04:00
Zach Hilman
06824e3c23 Finish abstract Vfs classes 2018-06-17 20:19:10 -04:00
Zach Hilman
87c7054be7 Add VfsFile and VfsDirectory classes 2018-06-16 23:09:10 -04:00
11 changed files with 574 additions and 57 deletions

View File

@@ -60,6 +60,7 @@ add_library(common STATIC
scm_rev.cpp
scm_rev.h
scope_exit.h
std_filesystem.h
string_util.cpp
string_util.h
swap.h

View File

@@ -388,7 +388,7 @@ u64 GetSize(FILE* f) {
bool CreateEmptyFile(const std::string& filename) {
NGLOG_TRACE(Common_Filesystem, "{}", filename);
if (!FileUtil::IOFile(filename, "wb")) {
if (!FileUtil::IOFile(filename, "wb").IsOpen()) {
NGLOG_ERROR(Common_Filesystem, "failed {}: {}", filename, GetLastErrorMsg());
return false;
}
@@ -750,7 +750,7 @@ size_t WriteStringToFile(bool text_file, const std::string& str, const char* fil
size_t ReadFileToString(bool text_file, const char* filename, std::string& str) {
IOFile file(filename, text_file ? "r" : "rb");
if (!file)
if (!file.IsOpen())
return false;
str.resize(static_cast<u32>(file.GetSize()));
@@ -820,7 +820,6 @@ IOFile& IOFile::operator=(IOFile&& other) noexcept {
void IOFile::Swap(IOFile& other) noexcept {
std::swap(m_file, other.m_file);
std::swap(m_good, other.m_good);
}
bool IOFile::Open(const std::string& filename, const char openmode[]) {
@@ -832,16 +831,15 @@ bool IOFile::Open(const std::string& filename, const char openmode[]) {
m_file = fopen(filename.c_str(), openmode);
#endif
m_good = IsOpen();
return m_good;
return IsOpen();
}
bool IOFile::Close() {
if (!IsOpen() || 0 != std::fclose(m_file))
m_good = false;
return false;
m_file = nullptr;
return m_good;
return true;
}
u64 IOFile::GetSize() const {
@@ -851,11 +849,8 @@ u64 IOFile::GetSize() const {
return 0;
}
bool IOFile::Seek(s64 off, int origin) {
if (!IsOpen() || 0 != fseeko(m_file, off, origin))
m_good = false;
return m_good;
bool IOFile::Seek(s64 off, int origin) const {
return IsOpen() && 0 == fseeko(m_file, off, origin);
}
u64 IOFile::Tell() const {
@@ -866,26 +861,20 @@ u64 IOFile::Tell() const {
}
bool IOFile::Flush() {
if (!IsOpen() || 0 != std::fflush(m_file))
m_good = false;
return m_good;
return IsOpen() && 0 == std::fflush(m_file);
}
bool IOFile::Resize(u64 size) {
if (!IsOpen() || 0 !=
return IsOpen() && 0 ==
#ifdef _WIN32
// ector: _chsize sucks, not 64-bit safe
// F|RES: changed to _chsize_s. i think it is 64-bit safe
_chsize_s(_fileno(m_file), size)
// ector: _chsize sucks, not 64-bit safe
// F|RES: changed to _chsize_s. i think it is 64-bit safe
_chsize_s(_fileno(m_file), size)
#else
// TODO: handle 64bit and growing
ftruncate(fileno(m_file), size)
// TODO: handle 64bit and growing
ftruncate(fileno(m_file), size)
#endif
)
m_good = false;
return m_good;
;
}
} // namespace FileUtil

View File

@@ -169,41 +169,27 @@ public:
bool Close();
template <typename T>
size_t ReadArray(T* data, size_t length) {
size_t ReadArray(T* data, size_t length) const {
static_assert(std::is_trivially_copyable<T>(),
"Given array does not consist of trivially copyable objects");
if (!IsOpen()) {
m_good = false;
if (!IsOpen())
return -1;
}
size_t items_read = std::fread(data, sizeof(T), length, m_file);
if (items_read != length)
m_good = false;
return items_read;
return std::fread(data, sizeof(T), length, m_file);
}
template <typename T>
size_t WriteArray(const T* data, size_t length) {
static_assert(std::is_trivially_copyable<T>(),
"Given array does not consist of trivially copyable objects");
if (!IsOpen()) {
m_good = false;
if (!IsOpen())
return -1;
}
size_t items_written = std::fwrite(data, sizeof(T), length, m_file);
if (items_written != length)
m_good = false;
return items_written;
return std::fwrite(data, sizeof(T), length, m_file);
}
template <typename T>
size_t ReadBytes(T* data, size_t length) {
size_t ReadBytes(T* data, size_t length) const {
static_assert(std::is_trivially_copyable<T>(), "T must be trivially copyable");
return ReadArray(reinterpret_cast<char*>(data), length);
}
@@ -224,15 +210,7 @@ public:
return nullptr != m_file;
}
// m_good is set to false when a read, write or other function fails
bool IsGood() const {
return m_good;
}
explicit operator bool() const {
return IsGood();
}
bool Seek(s64 off, int origin);
bool Seek(s64 off, int origin) const;
u64 Tell() const;
u64 GetSize() const;
bool Resize(u64 size);
@@ -240,13 +218,11 @@ public:
// clear error state
void Clear() {
m_good = true;
std::clearerr(m_file);
}
private:
std::FILE* m_file = nullptr;
bool m_good = true;
};
} // namespace FileUtil

View File

@@ -0,0 +1,13 @@
// Copyright 2018 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#ifdef _MSC_VER
#include <filesystem>
namespace filesystem = std::filesystem;
#else
#include <experimental/filesystem>
namespace filesystem = std::experimental::filesystem;
#endif

View File

@@ -29,6 +29,12 @@ add_library(core STATIC
file_sys/sdmc_factory.cpp
file_sys/sdmc_factory.h
file_sys/storage.h
file_sys/vfs.cpp
file_sys/vfs.h
file_sys/vfs_offset.cpp
file_sys/vfs_offset.h
file_sys/vfs_real.cpp
file_sys/vfs_real.h
frontend/emu_window.cpp
frontend/emu_window.h
frontend/framebuffer_layout.cpp

111
src/core/file_sys/vfs.cpp Normal file
View File

@@ -0,0 +1,111 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <numeric>
#include "core/file_sys/vfs.h"
namespace FileSys {
VfsFile::~VfsFile() = default;
VfsDirectory::~VfsDirectory() = default;
boost::optional<u8> VfsFile::ReadByte(size_t offset) const {
u8 out{};
size_t size = Read(&out, 1, offset);
if (size == 1)
return out;
return boost::none;
}
std::vector<u8> VfsFile::ReadBytes(size_t size, size_t offset) const {
std::vector<u8> out(size);
size_t read_size = Read(out.data(), size, offset);
out.resize(read_size);
return out;
}
std::vector<u8> VfsFile::ReadAllBytes() const {
return ReadBytes(GetSize());
}
bool VfsFile::WriteByte(u8 data, size_t offset) {
return 1 == Write(&data, 1, offset);
}
size_t VfsFile::WriteBytes(std::vector<u8> data, size_t offset) {
return Write(data.data(), data.size(), offset);
}
std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(const filesystem::path& path) const {
if (path.parent_path() == path.root_path())
return GetFile(path.filename().string());
auto parent = path.parent_path().string();
parent.replace(path.root_path().string().begin(), path.root_path().string().end(), "");
const auto index = parent.find_first_of('\\');
const auto first_dir = parent.substr(0, index), rest = parent.substr(index + 1);
const auto sub = GetSubdirectory(first_dir);
if (sub == nullptr)
return nullptr;
return sub->GetFileRelative(path.root_path().string() + rest);
}
std::shared_ptr<VfsFile> VfsDirectory::GetFileAbsolute(const filesystem::path& path) const {
if (IsRoot())
return GetFileRelative(path);
return GetParentDirectory()->GetFileAbsolute(path);
}
std::shared_ptr<VfsFile> VfsDirectory::GetFile(const std::string& name) const {
const auto& files = GetFiles();
const auto& iter = std::find_if(files.begin(), files.end(), [&name](const auto& file1) {
return name == file1->GetName();
});
return iter == files.end() ? nullptr : *iter;
}
std::shared_ptr<VfsDirectory> VfsDirectory::GetSubdirectory(const std::string& name) const {
const auto& subs = GetSubdirectories();
const auto& iter = std::find_if(
subs.begin(), subs.end(), [&name](const auto& file1) { return name == file1->GetName(); });
return iter == subs.end() ? nullptr : std::move(*iter);
}
bool VfsDirectory::IsRoot() const {
return GetParentDirectory() == nullptr;
}
size_t VfsDirectory::GetSize() const {
const auto& files = GetFiles();
const auto file_total =
std::accumulate(files.begin(), files.end(), 0ull,
[](const auto& f1, const auto& f2) { return f1 + f2->GetSize(); });
const auto& sub_dir = GetSubdirectories();
const auto subdir_total =
std::accumulate(sub_dir.begin(), sub_dir.end(), 0ull,
[](const auto& f1, const auto& f2) { return f1 + f2->GetSize(); });
return file_total + subdir_total;
}
bool VfsDirectory::Copy(const std::string& src, const std::string& dest) {
const auto f1 = CreateFile(src);
auto f2 = CreateFile(dest);
if (f1 == nullptr || f2 == nullptr)
return false;
if (!f2->Resize(f1->GetSize())) {
DeleteFile(dest);
return false;
}
return f2->WriteBytes(f1->ReadAllBytes()) == f1->GetSize();
}
} // namespace FileSys

117
src/core/file_sys/vfs.h Normal file
View File

@@ -0,0 +1,117 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <string>
#include <type_traits>
#include <vector>
#include "boost/optional.hpp"
#include "common/common_types.h"
#include "common/file_util.h"
#include "common/std_filesystem.h"
namespace FileSys {
struct VfsDirectory;
struct VfsFile : NonCopyable {
virtual ~VfsFile();
virtual std::string GetName() const = 0;
virtual size_t GetSize() const = 0;
virtual bool Resize(size_t new_size) = 0;
virtual std::shared_ptr<VfsDirectory> GetContainingDirectory() const = 0;
virtual bool IsWritable() const = 0;
virtual bool IsReadable() const = 0;
virtual size_t Read(u8* data, size_t length, size_t offset = 0) const = 0;
virtual size_t Write(const u8* data, size_t length, size_t offset = 0) = 0;
virtual boost::optional<u8> ReadByte(size_t offset = 0) const;
virtual std::vector<u8> ReadBytes(size_t size, size_t offset = 0) const;
virtual std::vector<u8> ReadAllBytes() const;
template <typename T>
size_t ReadArray(T* data, size_t number_elements, size_t offset = 0) const {
static_assert(std::is_trivially_copyable<T>::value,
"Data type must be trivially copyable.");
return Read(data, number_elements * sizeof(T), offset);
}
template <typename T>
size_t ReadBytes(T* data, size_t size, size_t offset = 0) const {
static_assert(std::is_trivially_copyable<T>::value,
"Data type must be trivially copyable.");
return Read(reinterpret_cast<u8*>(data), size, offset);
}
template <typename T>
size_t ReadObject(T& data, size_t offset = 0) const {
static_assert(std::is_trivially_copyable<T>::value,
"Data type must be trivially copyable.");
return Read(&data, sizeof(T), offset);
}
virtual bool WriteByte(u8 data, size_t offset = 0);
virtual size_t WriteBytes(std::vector<u8> data, size_t offset = 0);
template <typename T>
size_t WriteArray(T* data, size_t number_elements, size_t offset = 0) {
static_assert(std::is_trivially_copyable<T>::value,
"Data type must be trivially copyable.");
return Write(data, number_elements * sizeof(T), offset);
}
template <typename T>
size_t WriteBytes(T* data, size_t size, size_t offset = 0) {
static_assert(std::is_trivially_copyable<T>::value,
"Data type must be trivially copyable.");
return Write(reinterpret_cast<u8*>(data), size, offset);
}
template <typename T>
size_t WriteObject(T& data, size_t offset = 0) {
static_assert(std::is_trivially_copyable<T>::value,
"Data type must be trivially copyable.");
return Write(&data, sizeof(T), offset);
}
virtual bool Rename(const std::string& name) = 0;
};
struct VfsDirectory : NonCopyable {
virtual ~VfsDirectory();
virtual std::shared_ptr<VfsFile> GetFileRelative(const filesystem::path& path) const;
virtual std::shared_ptr<VfsFile> GetFileAbsolute(const filesystem::path& path) const;
virtual std::vector<std::shared_ptr<VfsFile>> GetFiles() const = 0;
virtual std::shared_ptr<VfsFile> GetFile(const std::string& name) const;
virtual std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const = 0;
virtual std::shared_ptr<VfsDirectory> GetSubdirectory(const std::string& name) const;
virtual bool IsWritable() const = 0;
virtual bool IsReadable() const = 0;
virtual bool IsRoot() const;
virtual std::string GetName() const = 0;
virtual size_t GetSize() const;
virtual std::shared_ptr<VfsDirectory> GetParentDirectory() const = 0;
virtual std::shared_ptr<VfsDirectory> CreateSubdirectory(const std::string& name) = 0;
virtual std::shared_ptr<VfsFile> CreateFile(const std::string& name) = 0;
virtual bool DeleteSubdirectory(const std::string& name) = 0;
virtual bool DeleteFile(const std::string& name) = 0;
virtual bool Rename(const std::string& name) = 0;
virtual bool Copy(const std::string& src, const std::string& dest);
};
} // namespace FileSys

View File

@@ -0,0 +1,83 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/file_sys/vfs_offset.h"
namespace FileSys {
OffsetVfsFile::OffsetVfsFile(std::unique_ptr<VfsFile>&& file_, u64 offset_, u64 size_)
: file(std::move(file_)), offset(offset_), size(size_) {}
std::string OffsetVfsFile::GetName() const {
return file->GetName();
}
u64 OffsetVfsFile::GetSize() const {
return size;
}
bool OffsetVfsFile::Resize(u64 new_size) {
if (offset + new_size < file->GetSize()) {
size = new_size;
return true;
}
return false;
}
std::shared_ptr<VfsDirectory> OffsetVfsFile::GetContainingDirectory() const {
return file->GetContainingDirectory();
}
bool OffsetVfsFile::IsWritable() const {
return file->IsWritable();
}
bool OffsetVfsFile::IsReadable() const {
return file->IsReadable();
}
size_t OffsetVfsFile::Read(u8* data, size_t length, size_t r_offset) const {
return file->Read(data, TrimToFit(length, r_offset), offset + r_offset);
}
size_t OffsetVfsFile::Write(const u8* data, size_t length, size_t r_offset) {
return file->Write(data, TrimToFit(length, r_offset), offset + r_offset);
}
boost::optional<u8> OffsetVfsFile::ReadByte(size_t r_offset) const {
if (r_offset < size)
return file->ReadByte(offset + r_offset);
return boost::none;
}
std::vector<u8> OffsetVfsFile::ReadBytes(size_t r_size, size_t r_offset) const {
return file->ReadBytes(TrimToFit(r_size, r_offset), offset + r_offset);
}
std::vector<u8> OffsetVfsFile::ReadAllBytes() const {
return file->ReadBytes(size, offset);
}
bool OffsetVfsFile::WriteByte(u8 data, size_t r_offset) {
if (r_offset < size)
return file->WriteByte(data, offset + r_offset);
return false;
}
size_t OffsetVfsFile::WriteBytes(std::vector<u8> data, size_t r_offset) {
return file->Write(data.data(), TrimToFit(data.size(), r_offset), offset + r_offset);
}
bool OffsetVfsFile::Rename(const std::string& name) {
return file->Rename(name);
}
size_t OffsetVfsFile::TrimToFit(size_t r_size, size_t r_offset) const {
return std::max(std::min(size - r_offset, r_size), 0ull);
}
} // namespace FileSys

View File

@@ -0,0 +1,38 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/file_sys/vfs.h"
namespace FileSys {
struct OffsetVfsFile : public VfsFile {
OffsetVfsFile(std::unique_ptr<VfsFile>&& file, size_t offset, size_t size);
std::string GetName() const override;
size_t GetSize() const override;
bool Resize(size_t new_size) override;
std::shared_ptr<VfsDirectory> GetContainingDirectory() const override;
bool IsWritable() const override;
bool IsReadable() const override;
size_t Read(u8* data, size_t length, size_t offset) const override;
size_t Write(const u8* data, size_t length, size_t offset) override;
boost::optional<u8> ReadByte(size_t offset) const override;
std::vector<u8> ReadBytes(size_t size, size_t offset) const override;
std::vector<u8> ReadAllBytes() const override;
bool WriteByte(u8 data, size_t offset) override;
size_t WriteBytes(std::vector<u8> data, size_t offset) override;
bool Rename(const std::string& name) override;
private:
size_t TrimToFit(size_t r_size, size_t r_offset) const;
std::unique_ptr<VfsFile> file;
size_t offset;
size_t size;
};
} // namespace FileSys

View File

@@ -0,0 +1,128 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/logging/log.h"
#include "core/file_sys/vfs_real.h"
namespace FileSys {
static const char* PermissionsToCharArray(filesystem::perms perms) {
std::string out;
if ((perms & filesystem::perms::owner_read) != filesystem::perms::none)
out += "r";
if ((perms & filesystem::perms::owner_write) != filesystem::perms::none)
out += "w";
return out.c_str();
}
RealVfsFile::RealVfsFile(const filesystem::path& path_, filesystem::perms perms_)
: backing(path_.string(), PermissionsToCharArray(perms_)), path(path_), perms(perms_) {}
std::string RealVfsFile::GetName() const {
return path.filename().string();
}
size_t RealVfsFile::GetSize() const {
return backing.GetSize();
}
bool RealVfsFile::Resize(size_t new_size) {
return backing.Resize(new_size);
}
std::shared_ptr<VfsDirectory> RealVfsFile::GetContainingDirectory() const {
return std::make_shared<RealVfsDirectory>(path.parent_path(), perms);
}
bool RealVfsFile::IsWritable() const {
return (perms & filesystem::perms::owner_write) != filesystem::perms::none;
}
bool RealVfsFile::IsReadable() const {
return (perms & filesystem::perms::owner_read) != filesystem::perms::none;
}
size_t RealVfsFile::Read(u8* data, size_t length, size_t offset) const {
if (!backing.Seek(offset, SEEK_SET))
return 0;
return backing.ReadBytes(data, length);
}
size_t RealVfsFile::Write(const u8* data, size_t length, size_t offset) {
if (!backing.Seek(offset, SEEK_SET))
return 0;
return backing.WriteBytes(data, length);
}
bool RealVfsFile::Rename(const std::string& name) {
const auto out = FileUtil::Rename(GetName(), name);
path = path.parent_path() / name;
backing = FileUtil::IOFile(path.string(), PermissionsToCharArray(perms));
return out;
}
RealVfsDirectory::RealVfsDirectory(const filesystem::path& path_, filesystem::perms perms_)
: path(path_), perms(perms_) {
for (const auto& entry : filesystem::directory_iterator(path)) {
if (filesystem::is_directory(entry.path()))
subdirectories.emplace_back(std::make_shared<RealVfsDirectory>(entry.path(), perms));
else if (filesystem::is_regular_file(entry.path()))
files.emplace_back(std::make_shared<RealVfsFile>(entry.path(), perms));
}
}
std::vector<std::shared_ptr<VfsFile>> RealVfsDirectory::GetFiles() const {
return std::vector<std::shared_ptr<VfsFile>>(files);
}
std::vector<std::shared_ptr<VfsDirectory>> RealVfsDirectory::GetSubdirectories() const {
return std::vector<std::shared_ptr<VfsDirectory>>(subdirectories);
}
bool RealVfsDirectory::IsWritable() const {
return (perms & filesystem::perms::owner_write) != filesystem::perms::none;
}
bool RealVfsDirectory::IsReadable() const {
return (perms & filesystem::perms::owner_read) != filesystem::perms::none;
}
std::string RealVfsDirectory::GetName() const {
return path.filename().string();
}
std::shared_ptr<VfsDirectory> RealVfsDirectory::GetParentDirectory() const {
if (path.parent_path() == path.root_path())
return nullptr;
return std::make_shared<RealVfsDirectory>(path.parent_path(), perms);
}
std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateSubdirectory(const std::string& name) {
if (!FileUtil::CreateDir((path / name).string()))
return nullptr;
subdirectories.emplace_back(std::make_shared<RealVfsDirectory>(path / name, perms));
return subdirectories.back();
}
std::shared_ptr<VfsFile> RealVfsDirectory::CreateFile(const std::string& name) {
if (!FileUtil::CreateEmptyFile((path / name).string()))
return nullptr;
files.emplace_back(std::make_shared<RealVfsFile>(path / name, perms));
return files.back();
}
bool RealVfsDirectory::DeleteSubdirectory(const std::string& name) {
return FileUtil::DeleteDirRecursively((path / name).string());
}
bool RealVfsDirectory::DeleteFile(const std::string& name) {
return FileUtil::Delete((path / name).string());
}
bool RealVfsDirectory::Rename(const std::string& name) {
return FileUtil::Rename(path.string(), (path / name).string());
}
} // namespace FileSys

View File

@@ -0,0 +1,55 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <filesystem>
#include "common/file_util.h"
#include "core/file_sys/vfs.h"
namespace FileSys {
struct RealVfsFile : public VfsFile {
RealVfsFile(const filesystem::path& name, filesystem::perms perms);
std::string GetName() const override;
size_t GetSize() const override;
bool Resize(size_t new_size) override;
std::shared_ptr<VfsDirectory> GetContainingDirectory() const override;
bool IsWritable() const override;
bool IsReadable() const override;
size_t Read(u8* data, size_t length, size_t offset) const override;
size_t Write(const u8* data, size_t length, size_t offset) override;
bool Rename(const std::string& name) override;
private:
FileUtil::IOFile backing;
filesystem::path path;
filesystem::perms perms;
};
struct RealVfsDirectory : public VfsDirectory {
RealVfsDirectory(const filesystem::path& path, filesystem::perms perms);
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
bool IsWritable() const override;
bool IsReadable() const override;
bool IsRoot() const override;
std::string GetName() const override;
std::shared_ptr<VfsDirectory> GetParentDirectory() const override;
std::shared_ptr<VfsDirectory> CreateSubdirectory(const std::string& name) override;
std::shared_ptr<VfsFile> CreateFile(const std::string& name) override;
bool DeleteSubdirectory(const std::string& name) override;
bool DeleteFile(const std::string& name) override;
bool Rename(const std::string& name) override;
private:
filesystem::path path;
filesystem::perms perms;
std::vector<std::shared_ptr<VfsFile>> files;
std::vector<std::shared_ptr<VfsDirectory>> subdirectories;
};
} // namespace FileSys