Major refactor

This commit is contained in:
Zach Hilman
2018-06-23 16:11:38 -04:00
parent 86a4544aee
commit c4033094a1
8 changed files with 306 additions and 308 deletions

View File

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

View File

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

View File

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

View File

@@ -4,7 +4,9 @@
#pragma once #pragma once
#include <filesystem>
#include <string> #include <string>
#include <type_traits>
#include <vector> #include <vector>
#include "boost/optional.hpp" #include "boost/optional.hpp"
#include "common/common_types.h" #include "common/common_types.h"
@@ -13,82 +15,93 @@ namespace FileSys {
struct VfsDirectory; struct VfsDirectory;
struct VfsFile : NonCopyable { struct VfsFile : NonCopyable {
virtual bool IsReady() = 0; virtual ~VfsFile();
virtual bool IsGood() = 0;
virtual operator bool();
virtual void ResetState() = 0;
virtual std::string GetName() = 0; virtual std::string GetName() const = 0;
virtual u64 GetSize() = 0; virtual size_t GetSize() const = 0;
virtual bool Resize(u64 new_size) = 0; virtual bool Resize(size_t new_size) = 0;
virtual std::shared_ptr<VfsDirectory> GetContainingDirectory() = 0; virtual std::shared_ptr<VfsDirectory> GetContainingDirectory() const = 0;
virtual bool IsWritable() = 0; virtual bool IsWritable() const = 0;
virtual bool IsReadable() = 0; virtual bool IsReadable() const = 0;
virtual boost::optional<u8> ReadByte(u64 offset); virtual size_t Read(u8* data, size_t length, size_t offset = 0) const = 0;
virtual std::vector<u8> ReadBytes(u64 offset, u64 length) = 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> template <typename T>
u64 ReadBytes(T* data, u64 offset, u64 length) { size_t ReadArray(T* data, size_t number_elements, size_t offset = 0) const {
static_assert(std::is_trivially_copyable<T>(), static_assert(std::is_trivially_copyable<T>::value,
"Given array does not consist of trivially copyable objects"); "Data type must be trivially copyable.");
return ReadArray<u8>(reinterpret_cast<u8*>(data), offset, length);
return Read(data, number_elements * sizeof(T), offset);
} }
template <typename T> template <typename T>
std::vector<T> ReadArray(u64 offset, u64 number_elements) { size_t ReadBytes(T* data, size_t size, size_t offset = 0) const {
static_assert(std::is_trivially_copyable<T>(), static_assert(std::is_trivially_copyable<T>::value,
"Given array does not consist of trivially copyable objects"); "Data type must be trivially copyable.");
return Read(reinterpret_cast<u8*>(data), size, offset);
auto vec = ReadBytes(offset, number_elements * sizeof(T));
std::vector<T> out_vec(number_elements);
memcpy(out_vec.data(), vec.data(), vec.size());
return out_vec;
} }
template <typename T> template <typename T>
u64 ReadArray(T* data, u64 offset, u64 number_elements) { size_t ReadObject(T& data, size_t offset = 0) const {
static_assert(std::is_trivially_copyable<T>(), static_assert(std::is_trivially_copyable<T>::value,
"Given array does not consist of trivially copyable objects"); "Data type must be trivially copyable.");
return Read(&data, sizeof(T), offset);
std::vector<T> vec = ReadArray<T>(offset, number_elements);
for (size_t i = 0; i < vec.size(); ++i)
data[i] = vec[i];
return vec.size();
} }
virtual std::vector<u8> ReadAllBytes(); virtual bool WriteByte(u8 data, size_t offset = 0);
virtual size_t WriteBytes(std::vector<u8> data, size_t offset = 0);
virtual u64 WriteBytes(const std::vector<u8>& data, u64 offset) = 0; template <typename T>
virtual u64 ReplaceBytes(const std::vector<u8>& data); 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; virtual bool Rename(const std::string& name) = 0;
~VfsFile();
}; };
struct VfsDirectory : NonCopyable { struct VfsDirectory : NonCopyable {
virtual bool IsReady() = 0; virtual ~VfsDirectory();
virtual bool IsGood() = 0;
virtual operator bool();
virtual void ResetState() = 0;
virtual std::vector<std::shared_ptr<VfsFile>> GetFiles() = 0; virtual std::shared_ptr<VfsFile> GetFileRelative(const std::filesystem::path& path) const;
virtual std::shared_ptr<VfsFile> GetFile(const std::string& name); virtual std::shared_ptr<VfsFile> GetFileAbsolute(const std::filesystem::path& path) const;
virtual std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() = 0; virtual std::vector<std::shared_ptr<VfsFile>> GetFiles() const = 0;
virtual std::shared_ptr<VfsDirectory> GetSubdirectory(const std::string& name); virtual std::shared_ptr<VfsFile> GetFile(const std::string& name) const;
virtual bool IsWritable() = 0; virtual std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const = 0;
virtual bool IsReadable() = 0; virtual std::shared_ptr<VfsDirectory> GetSubdirectory(const std::string& name) const;
virtual bool IsRoot() = 0; virtual bool IsWritable() const = 0;
virtual bool IsReadable() const = 0;
virtual std::string GetName() = 0; virtual bool IsRoot() const;
virtual u64 GetSize();
virtual std::shared_ptr<VfsDirectory> GetParentDirectory() = 0; 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<VfsDirectory> CreateSubdirectory(const std::string& name) = 0;
virtual std::shared_ptr<VfsFile> CreateFile(const std::string& name) = 0; virtual std::shared_ptr<VfsFile> CreateFile(const std::string& name) = 0;
@@ -99,7 +112,5 @@ struct VfsDirectory : NonCopyable {
virtual bool Rename(const std::string& name) = 0; virtual bool Rename(const std::string& name) = 0;
virtual bool Copy(const std::string& src, const std::string& dest); virtual bool Copy(const std::string& src, const std::string& dest);
~VfsDirectory();
}; };
} // namespace FileSys } // namespace FileSys

View File

@@ -6,26 +6,14 @@
namespace FileSys { namespace FileSys {
OffsetVfsFile::OffsetVfsFile(std::unique_ptr<VfsFile>&& file, u64 offset, u64 size) OffsetVfsFile::OffsetVfsFile(std::unique_ptr<VfsFile>&& file_, u64 offset_, u64 size_)
: file(std::move(file)), offset(offset), size(size) {} : file(std::move(file_)), offset(offset_), size(size_) {}
bool OffsetVfsFile::IsReady() { std::string OffsetVfsFile::GetName() const {
return file->IsReady();
}
bool OffsetVfsFile::IsGood() {
return file->IsGood();
}
void OffsetVfsFile::ResetState() {
file->ResetState();
}
std::string OffsetVfsFile::GetName() {
return file->GetName(); return file->GetName();
} }
u64 OffsetVfsFile::GetSize() { u64 OffsetVfsFile::GetSize() const {
return size; return size;
} }
@@ -38,32 +26,58 @@ bool OffsetVfsFile::Resize(u64 new_size) {
return false; return false;
} }
std::shared_ptr<VfsDirectory> OffsetVfsFile::GetContainingDirectory() { std::shared_ptr<VfsDirectory> OffsetVfsFile::GetContainingDirectory() const {
return file->GetContainingDirectory(); return file->GetContainingDirectory();
} }
bool OffsetVfsFile::IsWritable() { bool OffsetVfsFile::IsWritable() const {
return file->IsWritable(); return file->IsWritable();
} }
bool OffsetVfsFile::IsReadable() { bool OffsetVfsFile::IsReadable() const {
return file->IsReadable(); return file->IsReadable();
} }
std::vector<u8> OffsetVfsFile::ReadBytes(u64 r_offset, u64 r_length) { size_t OffsetVfsFile::Read(u8* data, size_t length, size_t r_offset) const {
return file->ReadBytes(offset + r_offset, std::min(r_offset + r_length, size)); return file->Read(data, TrimToFit(length, r_offset), offset + r_offset);
} }
u64 OffsetVfsFile::WriteBytes(const std::vector<u8>& data, u64 r_offset) { size_t OffsetVfsFile::Write(const u8* data, size_t length, size_t r_offset) {
auto end = data.end(); return file->Write(data, TrimToFit(length, r_offset), offset + r_offset);
if (data.size() + r_offset > size) }
end = data.begin() + size - r_offset;
return file->WriteBytes(std::vector<u8>(data.begin(), end), r_offset + 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) { bool OffsetVfsFile::Rename(const std::string& name) {
return file->Rename(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 } // namespace FileSys

View File

@@ -3,30 +3,36 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#pragma once #pragma once
#include "core/file_sys/vfs.h" #include "core/file_sys/vfs.h"
namespace FileSys { namespace FileSys {
struct OffsetVfsFile : public VfsFile { struct OffsetVfsFile : public VfsFile {
OffsetVfsFile(std::unique_ptr<VfsFile>&& file, u64 offset, u64 size); 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 IsReady() override;
bool IsGood() override;
void ResetState() override;
std::string GetName() override;
u64 GetSize() override;
bool Resize(u64 new_size) override;
std::shared_ptr<VfsDirectory> GetContainingDirectory() override;
bool IsWritable() override;
bool IsReadable() override;
std::vector<u8> ReadBytes(u64 offset, u64 length) override;
u64 WriteBytes(const std::vector<u8>& data, u64 offset) override;
bool Rename(const std::string& name) override; bool Rename(const std::string& name) override;
private: private:
size_t TrimToFit(size_t r_size, size_t r_offset) const;
std::unique_ptr<VfsFile> file; std::unique_ptr<VfsFile> file;
u64 offset; size_t offset;
u64 size; size_t size;
}; };
} // namespace FileSys } // namespace FileSys

View File

@@ -2,160 +2,128 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "common/common_paths.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/file_sys/vfs_real.h" #include "core/file_sys/vfs_real.h"
namespace FileSys { namespace FileSys {
RealVfsFile::RealVfsFile(const std::string& path, const char openmode[]) static const char* PermissionsToCharArray(std::filesystem::perms perms) {
: backing(path, openmode), path(path), mode(openmode) {} std::string out;
if ((perms & std::filesystem::perms::owner_read) != std::filesystem::perms::none)
bool RealVfsFile::IsReady() { out += "r";
return backing.IsOpen(); if ((perms & std::filesystem::perms::owner_write) != std::filesystem::perms::none)
out += "w";
return out.c_str();
} }
bool RealVfsFile::IsGood() { RealVfsFile::RealVfsFile(const std::filesystem::path& path_, std::filesystem::perms perms_)
return backing.IsGood(); : backing(path_.string(), PermissionsToCharArray(perms_)), path(path_), perms(perms_) {}
std::string RealVfsFile::GetName() const {
return path.filename().string();
} }
void RealVfsFile::ResetState() { size_t RealVfsFile::GetSize() const {
backing.Clear();
}
std::string RealVfsFile::GetName() {
std::string part_path, name, extention;
Common::SplitPath(path, &part_path, &name, &extention);
return name + "." + extention;
}
u64 RealVfsFile::GetSize() {
return backing.GetSize(); return backing.GetSize();
} }
bool RealVfsFile::Resize(u64 new_size) { bool RealVfsFile::Resize(size_t new_size) {
return backing.Resize(new_size); return backing.Resize(new_size);
} }
std::shared_ptr<VfsDirectory> RealVfsFile::GetContainingDirectory() { std::shared_ptr<VfsDirectory> RealVfsFile::GetContainingDirectory() const {
std::string part_path, name, extention; return std::make_shared<RealVfsDirectory>(path.parent_path(), perms);
Common::SplitPath(path, &part_path, &name, &extention);
return std::make_shared<RealVfsDirectory>(part_path, mode.c_str());
} }
bool RealVfsFile::IsWritable() { bool RealVfsFile::IsWritable() const {
return mode.find('w') != std::string::npos; return (perms & std::filesystem::perms::owner_write) != std::filesystem::perms::none;
} }
bool RealVfsFile::IsReadable() { bool RealVfsFile::IsReadable() const {
return mode.find('r') != std::string::npos; return (perms & std::filesystem::perms::owner_read) != std::filesystem::perms::none;
} }
std::vector<u8> RealVfsFile::ReadBytes(u64 offset, u64 length) { size_t RealVfsFile::Read(u8* data, size_t length, size_t offset) const {
backing.Seek(offset, SEEK_SET); if (!backing.Seek(offset, SEEK_SET))
std::vector<u8> out(length); return 0;
backing.ReadBytes(out.data(), length); return backing.ReadBytes(data, length);
return out;
} }
u64 RealVfsFile::WriteBytes(const std::vector<u8>& data, u64 offset) { size_t RealVfsFile::Write(const u8* data, size_t length, size_t offset) {
backing.Seek(offset, SEEK_SET); if (!backing.Seek(offset, SEEK_SET))
return backing.WriteBytes(data.data(), data.size()); return 0;
return backing.WriteBytes(data, length);
} }
bool RealVfsFile::Rename(const std::string& name) { bool RealVfsFile::Rename(const std::string& name) {
auto out = FileUtil::Rename(GetName(), name); const auto out = FileUtil::Rename(GetName(), name);
std::string part_path, o_name, extention; path = path.parent_path() / name;
Common::SplitPath(path, &part_path, &o_name, &extention); backing = FileUtil::IOFile(path.string(), PermissionsToCharArray(perms));
backing = FileUtil::IOFile(part_path + name, mode.c_str());
return out; return out;
} }
RealVfsDirectory::RealVfsDirectory(const std::string& path, const char openmode[]) RealVfsDirectory::RealVfsDirectory(const std::filesystem::path& path_,
: path(path[path.size() - 1] == DIR_SEP_CHR ? path.substr(0, path.size() - 1) : path) { std::filesystem::perms perms_)
FileUtil::FSTEntry entry; : path(path_), perms(perms_) {
if (0 != FileUtil::ScanDirectoryTree(path, entry)) for (const auto& entry : std::filesystem::directory_iterator(path)) {
NGLOG_CRITICAL(Service_FS, "Failure to initialize file."); if (std::filesystem::is_directory(entry.path()))
for (FileUtil::FSTEntry child : entry.children) { subdirectories.emplace_back(std::make_shared<RealVfsDirectory>(entry.path(), perms));
if (child.isDirectory) else if (std::filesystem::is_regular_file(entry.path()))
subdirectories.emplace_back( files.emplace_back(std::make_shared<RealVfsFile>(entry.path(), perms));
std::make_shared<RealVfsDirectory>(child.physicalName, mode.c_str()));
else
files.emplace_back(std::make_shared<RealVfsFile>(child.physicalName, mode.c_str()));
} }
} }
bool RealVfsDirectory::IsReady() { std::vector<std::shared_ptr<VfsFile>> RealVfsDirectory::GetFiles() const {
return FileUtil::IsDirectory(path);
}
bool RealVfsDirectory::IsGood() {
return FileUtil::IsDirectory(path);
}
void RealVfsDirectory::ResetState() {}
std::vector<std::shared_ptr<VfsFile>> RealVfsDirectory::GetFiles() {
return std::vector<std::shared_ptr<VfsFile>>(files); return std::vector<std::shared_ptr<VfsFile>>(files);
} }
std::vector<std::shared_ptr<VfsDirectory>> RealVfsDirectory::GetSubdirectories() { std::vector<std::shared_ptr<VfsDirectory>> RealVfsDirectory::GetSubdirectories() const {
return std::vector<std::shared_ptr<VfsDirectory>>(subdirectories); return std::vector<std::shared_ptr<VfsDirectory>>(subdirectories);
} }
bool RealVfsDirectory::IsWritable() { bool RealVfsDirectory::IsWritable() const {
return mode.find('w') != std::string::npos; return (perms & std::filesystem::perms::owner_write) != std::filesystem::perms::none;
} }
bool RealVfsDirectory::IsReadable() { bool RealVfsDirectory::IsReadable() const {
return mode.find('r') != std::string::npos; return (perms & std::filesystem::perms::owner_read) != std::filesystem::perms::none;
} }
bool RealVfsDirectory::IsRoot() { std::string RealVfsDirectory::GetName() const {
return path.empty() || (path.size() == 2 && path[1] == ':'); return path.filename().string();
} }
std::string RealVfsDirectory::GetName() { std::shared_ptr<VfsDirectory> RealVfsDirectory::GetParentDirectory() const {
size_t last = path.rfind(DIR_SEP_CHR); if (path.parent_path() == path.root_path())
return path.substr(last + 1);
}
std::shared_ptr<VfsDirectory> RealVfsDirectory::GetParentDirectory() {
size_t last = path.rfind(DIR_SEP_CHR);
if (last == path.size() - 1)
last = path.rfind(DIR_SEP_CHR, path.size() - 2);
if (last == std::string::npos)
return nullptr; return nullptr;
return std::make_shared<RealVfsDirectory>(path.substr(0, last), mode.c_str()); return std::make_shared<RealVfsDirectory>(path.parent_path(), perms);
} }
std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateSubdirectory(const std::string& name) { std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateSubdirectory(const std::string& name) {
FileUtil::CreateDir(path + DIR_SEP + name); if (!FileUtil::CreateDir((path / name).string()))
subdirectories.emplace_back( return nullptr;
std::make_shared<RealVfsDirectory>(path + DIR_SEP + name, mode.c_str())); subdirectories.emplace_back(std::make_shared<RealVfsDirectory>(path / name, perms));
return subdirectories[subdirectories.size() - 1]; return subdirectories.back();
} }
std::shared_ptr<VfsFile> RealVfsDirectory::CreateFile(const std::string& name) { std::shared_ptr<VfsFile> RealVfsDirectory::CreateFile(const std::string& name) {
FileUtil::CreateEmptyFile(path + DIR_SEP + name); if (!FileUtil::CreateEmptyFile((path / name).string()))
files.emplace_back(std::make_shared<RealVfsFile>(path + DIR_SEP + name, mode.c_str())); return nullptr;
return files[files.size() - 1]; files.emplace_back(std::make_shared<RealVfsFile>(path / name, perms));
return files.back();
} }
bool RealVfsDirectory::DeleteSubdirectory(const std::string& name) { bool RealVfsDirectory::DeleteSubdirectory(const std::string& name) {
return FileUtil::DeleteDirRecursively(path + DIR_SEP + name); return FileUtil::DeleteDirRecursively((path / name).string());
} }
bool RealVfsDirectory::DeleteFile(const std::string& name) { bool RealVfsDirectory::DeleteFile(const std::string& name) {
return FileUtil::Delete(path + DIR_SEP + name); return FileUtil::Delete((path / name).string());
} }
bool RealVfsDirectory::Rename(const std::string& name) { bool RealVfsDirectory::Rename(const std::string& name) {
std::string part, o_name, extention; return FileUtil::Rename(path.string(), (path / name).string());
Common::SplitPath(name, &part, &o_name, &extention);
return FileUtil::Rename(path, part + DIR_SEP + name);
} }
} // namespace FileSys } // namespace FileSys

View File

@@ -3,46 +3,42 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#pragma once #pragma once
#include <filesystem>
#include "common/file_util.h" #include "common/file_util.h"
#include "core/file_sys/vfs.h" #include "core/file_sys/vfs.h"
namespace FileSys { namespace FileSys {
struct RealVfsFile : public VfsFile { struct RealVfsFile : public VfsFile {
RealVfsFile(const std::string& name, const char openmode[]); RealVfsFile(const std::filesystem::path& name, std::filesystem::perms perms);
bool IsReady() override; std::string GetName() const override;
bool IsGood() override; size_t GetSize() const override;
void ResetState() override; bool Resize(size_t new_size) override;
std::string GetName() override; std::shared_ptr<VfsDirectory> GetContainingDirectory() const override;
u64 GetSize() override; bool IsWritable() const override;
bool Resize(u64 new_size) override; bool IsReadable() const override;
std::shared_ptr<VfsDirectory> GetContainingDirectory() override; size_t Read(u8* data, size_t length, size_t offset) const override;
bool IsWritable() override; size_t Write(const u8* data, size_t length, size_t offset) override;
bool IsReadable() override;
std::vector<u8> ReadBytes(u64 offset, u64 length) override;
u64 WriteBytes(const std::vector<u8>& data, u64 offset) override;
bool Rename(const std::string& name) override; bool Rename(const std::string& name) override;
private: private:
FileUtil::IOFile backing; FileUtil::IOFile backing;
std::string path; std::filesystem::path path;
std::string mode; std::filesystem::perms perms;
}; };
struct RealVfsDirectory : public VfsDirectory { struct RealVfsDirectory : public VfsDirectory {
RealVfsDirectory(const std::string& path, const char openmode[]); RealVfsDirectory(const std::filesystem::path& path, std::filesystem::perms perms);
bool IsReady() override; std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
bool IsGood() override; std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
void ResetState() override; bool IsWritable() const override;
std::vector<std::shared_ptr<VfsFile>> GetFiles() override; bool IsReadable() const override;
std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() override; bool IsRoot() const override;
bool IsWritable() override; std::string GetName() const override;
bool IsReadable() override; std::shared_ptr<VfsDirectory> GetParentDirectory() const override;
bool IsRoot() override;
std::string GetName() override;
std::shared_ptr<VfsDirectory> GetParentDirectory() override;
std::shared_ptr<VfsDirectory> CreateSubdirectory(const std::string& name) override; std::shared_ptr<VfsDirectory> CreateSubdirectory(const std::string& name) override;
std::shared_ptr<VfsFile> CreateFile(const std::string& name) override; std::shared_ptr<VfsFile> CreateFile(const std::string& name) override;
bool DeleteSubdirectory(const std::string& name) override; bool DeleteSubdirectory(const std::string& name) override;
@@ -50,8 +46,8 @@ struct RealVfsDirectory : public VfsDirectory {
bool Rename(const std::string& name) override; bool Rename(const std::string& name) override;
private: private:
std::string path; std::filesystem::path path;
std::string mode; std::filesystem::perms perms;
std::vector<std::shared_ptr<VfsFile>> files; std::vector<std::shared_ptr<VfsFile>> files;
std::vector<std::shared_ptr<VfsDirectory>> subdirectories; std::vector<std::shared_ptr<VfsDirectory>> subdirectories;
}; };