diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index 2d0b81c6ee..5cd8aea558 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp @@ -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(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 diff --git a/src/common/file_util.h b/src/common/file_util.h index fc6b3ea466..bb4d36dd64 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h @@ -169,41 +169,27 @@ public: bool Close(); template - size_t ReadArray(T* data, size_t length) { + size_t ReadArray(T* data, size_t length) const { static_assert(std::is_trivially_copyable(), "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 size_t WriteArray(const T* data, size_t length) { static_assert(std::is_trivially_copyable(), "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 - size_t ReadBytes(T* data, size_t length) { + size_t ReadBytes(T* data, size_t length) const { static_assert(std::is_trivially_copyable(), "T must be trivially copyable"); return ReadArray(reinterpret_cast(data), length); } @@ -220,19 +206,11 @@ public: return WriteArray(&object, 1); } - bool IsOpen() const { + bool IsOpen() const const { 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 diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp index 4b956f1fa9..4f877f9acc 100644 --- a/src/core/file_sys/vfs.cpp +++ b/src/core/file_sys/vfs.cpp @@ -2,72 +2,110 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include #include "core/file_sys/vfs.h" namespace FileSys { -VfsFile::operator bool() { - return IsGood(); +VfsFile::~VfsFile() = default; + +VfsDirectory::~VfsDirectory() = default; + +boost::optional 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 VfsFile::ReadByte(u64 offset) { - auto vec = ReadBytes(offset, 1); - if (vec.empty()) - return boost::none; - return vec[0]; +std::vector VfsFile::ReadBytes(size_t size, size_t offset) const { + std::vector out(size); + size_t read_size = Read(out.data(), size, offset); + out.resize(read_size); + return out; } -std::vector VfsFile::ReadAllBytes() { - return ReadBytes(0, GetSize()); +std::vector VfsFile::ReadAllBytes() const { + return ReadBytes(GetSize()); } -u64 VfsFile::ReplaceBytes(const std::vector& data) { - if (!Resize(data.size())) - return 0; - return WriteBytes(data, 0); +bool VfsFile::WriteByte(u8 data, size_t offset) { + return 1 == Write(&data, 1, offset); } -VfsDirectory::operator bool() { - return IsGood(); +size_t VfsFile::WriteBytes(std::vector data, size_t offset) { + return Write(data.data(), data.size(), offset); } -std::shared_ptr VfsDirectory::GetFile(const std::string& name) { - auto files = GetFiles(); - auto iter = std::find_if(files.begin(), files.end(), - [&name](auto file1) { return name == file1->GetName(); }); - return iter == files.end() ? nullptr : std::move(*iter); +std::shared_ptr VfsDirectory::GetFileRelative(const std::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 VfsDirectory::GetSubdirectory(const std::string& name) { - auto subs = GetSubdirectories(); - auto iter = std::find_if(subs.begin(), subs.end(), - [&name](auto file1) { return name == file1->GetName(); }); +std::shared_ptr VfsDirectory::GetFileAbsolute(const std::filesystem::path& path) const { + if (IsRoot()) + return GetFileRelative(path); + + return GetParentDirectory()->GetFileAbsolute(path); +} + +std::shared_ptr 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::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); } -u64 VfsDirectory::GetSize() { - auto files = GetFiles(); - auto file_total = std::accumulate(files.begin(), files.end(), 0ull, - [](auto f1, auto f2) { return f1 + f2->GetSize(); }); +bool VfsDirectory::IsRoot() const { + return GetParentDirectory() == nullptr; +} - auto sub_dir = GetSubdirectories(); - auto subdir_total = std::accumulate(sub_dir.begin(), sub_dir.end(), 0ull, - [](auto f1, auto f2) { return f1 + f2->GetSize(); }); +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) { - auto f1 = CreateFile(src), f2 = CreateFile(dest); + const auto f1 = CreateFile(src); + auto f2 = CreateFile(dest); if (f1 == nullptr || f2 == nullptr) 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 diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h index 42a024fbc0..570ffd6278 100644 --- a/src/core/file_sys/vfs.h +++ b/src/core/file_sys/vfs.h @@ -4,7 +4,9 @@ #pragma once +#include #include +#include #include #include "boost/optional.hpp" #include "common/common_types.h" @@ -13,82 +15,93 @@ namespace FileSys { struct VfsDirectory; struct VfsFile : NonCopyable { - virtual bool IsReady() = 0; - virtual bool IsGood() = 0; - virtual operator bool(); - virtual void ResetState() = 0; + virtual ~VfsFile(); - virtual std::string GetName() = 0; - virtual u64 GetSize() = 0; - virtual bool Resize(u64 new_size) = 0; - virtual std::shared_ptr GetContainingDirectory() = 0; + virtual std::string GetName() const = 0; + virtual size_t GetSize() const = 0; + virtual bool Resize(size_t new_size) = 0; + virtual std::shared_ptr GetContainingDirectory() const = 0; - virtual bool IsWritable() = 0; - virtual bool IsReadable() = 0; + virtual bool IsWritable() const = 0; + virtual bool IsReadable() const = 0; - virtual boost::optional ReadByte(u64 offset); - virtual std::vector ReadBytes(u64 offset, u64 length) = 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 ReadByte(size_t offset = 0) const; + virtual std::vector ReadBytes(size_t size, size_t offset = 0) const; + virtual std::vector ReadAllBytes() const; template - u64 ReadBytes(T* data, u64 offset, u64 length) { - static_assert(std::is_trivially_copyable(), - "Given array does not consist of trivially copyable objects"); - return ReadArray(reinterpret_cast(data), offset, length); + size_t ReadArray(T* data, size_t number_elements, size_t offset = 0) const { + static_assert(std::is_trivially_copyable::value, + "Data type must be trivially copyable."); + + return Read(data, number_elements * sizeof(T), offset); } template - std::vector ReadArray(u64 offset, u64 number_elements) { - static_assert(std::is_trivially_copyable(), - "Given array does not consist of trivially copyable objects"); - - auto vec = ReadBytes(offset, number_elements * sizeof(T)); - std::vector out_vec(number_elements); - memcpy(out_vec.data(), vec.data(), vec.size()); - return out_vec; + size_t ReadBytes(T* data, size_t size, size_t offset = 0) const { + static_assert(std::is_trivially_copyable::value, + "Data type must be trivially copyable."); + return Read(reinterpret_cast(data), size, offset); } template - u64 ReadArray(T* data, u64 offset, u64 number_elements) { - static_assert(std::is_trivially_copyable(), - "Given array does not consist of trivially copyable objects"); - - std::vector vec = ReadArray(offset, number_elements); - for (size_t i = 0; i < vec.size(); ++i) - data[i] = vec[i]; - - return vec.size(); + size_t ReadObject(T& data, size_t offset = 0) const { + static_assert(std::is_trivially_copyable::value, + "Data type must be trivially copyable."); + return Read(&data, sizeof(T), offset); } - virtual std::vector ReadAllBytes(); + virtual bool WriteByte(u8 data, size_t offset = 0); + virtual size_t WriteBytes(std::vector data, size_t offset = 0); - virtual u64 WriteBytes(const std::vector& data, u64 offset) = 0; - virtual u64 ReplaceBytes(const std::vector& data); + template + size_t WriteArray(T* data, size_t number_elements, size_t offset = 0) { + static_assert(std::is_trivially_copyable::value, + "Data type must be trivially copyable."); + + return Write(data, number_elements * sizeof(T), offset); + } + + template + size_t WriteBytes(T* data, size_t size, size_t offset = 0) { + static_assert(std::is_trivially_copyable::value, + "Data type must be trivially copyable."); + return Write(reinterpret_cast(data), size, offset); + } + + template + size_t WriteObject(T& data, size_t offset = 0) { + static_assert(std::is_trivially_copyable::value, + "Data type must be trivially copyable."); + return Write(&data, sizeof(T), offset); + } virtual bool Rename(const std::string& name) = 0; - - ~VfsFile(); }; struct VfsDirectory : NonCopyable { - virtual bool IsReady() = 0; - virtual bool IsGood() = 0; - virtual operator bool(); - virtual void ResetState() = 0; + virtual ~VfsDirectory(); - virtual std::vector> GetFiles() = 0; - virtual std::shared_ptr GetFile(const std::string& name); + virtual std::shared_ptr GetFileRelative(const std::filesystem::path& path) const; + virtual std::shared_ptr GetFileAbsolute(const std::filesystem::path& path) const; - virtual std::vector> GetSubdirectories() = 0; - virtual std::shared_ptr GetSubdirectory(const std::string& name); + virtual std::vector> GetFiles() const = 0; + virtual std::shared_ptr GetFile(const std::string& name) const; - virtual bool IsWritable() = 0; - virtual bool IsReadable() = 0; + virtual std::vector> GetSubdirectories() const = 0; + virtual std::shared_ptr 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 u64 GetSize(); - virtual std::shared_ptr GetParentDirectory() = 0; + virtual bool IsRoot() const; + + virtual std::string GetName() const = 0; + virtual size_t GetSize() const; + virtual std::shared_ptr GetParentDirectory() const = 0; virtual std::shared_ptr CreateSubdirectory(const std::string& name) = 0; virtual std::shared_ptr CreateFile(const std::string& name) = 0; @@ -99,7 +112,5 @@ struct VfsDirectory : NonCopyable { virtual bool Rename(const std::string& name) = 0; virtual bool Copy(const std::string& src, const std::string& dest); - - ~VfsDirectory(); }; } // namespace FileSys diff --git a/src/core/file_sys/vfs_offset.cpp b/src/core/file_sys/vfs_offset.cpp index 39d5d06cf6..bc3b16eb5b 100644 --- a/src/core/file_sys/vfs_offset.cpp +++ b/src/core/file_sys/vfs_offset.cpp @@ -6,26 +6,14 @@ namespace FileSys { -OffsetVfsFile::OffsetVfsFile(std::unique_ptr&& file, u64 offset, u64 size) - : file(std::move(file)), offset(offset), size(size) {} +OffsetVfsFile::OffsetVfsFile(std::unique_ptr&& file_, u64 offset_, u64 size_) + : file(std::move(file_)), offset(offset_), size(size_) {} -bool OffsetVfsFile::IsReady() { - return file->IsReady(); -} - -bool OffsetVfsFile::IsGood() { - return file->IsGood(); -} - -void OffsetVfsFile::ResetState() { - file->ResetState(); -} - -std::string OffsetVfsFile::GetName() { +std::string OffsetVfsFile::GetName() const { return file->GetName(); } -u64 OffsetVfsFile::GetSize() { +u64 OffsetVfsFile::GetSize() const { return size; } @@ -38,32 +26,58 @@ bool OffsetVfsFile::Resize(u64 new_size) { return false; } -std::shared_ptr OffsetVfsFile::GetContainingDirectory() { +std::shared_ptr OffsetVfsFile::GetContainingDirectory() const { return file->GetContainingDirectory(); } -bool OffsetVfsFile::IsWritable() { +bool OffsetVfsFile::IsWritable() const { return file->IsWritable(); } -bool OffsetVfsFile::IsReadable() { +bool OffsetVfsFile::IsReadable() const { return file->IsReadable(); } -std::vector OffsetVfsFile::ReadBytes(u64 r_offset, u64 r_length) { - return file->ReadBytes(offset + r_offset, std::min(r_offset + r_length, size)); +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); } -u64 OffsetVfsFile::WriteBytes(const std::vector& data, u64 r_offset) { - auto end = data.end(); - if (data.size() + r_offset > size) - end = data.begin() + size - 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); +} - return file->WriteBytes(std::vector(data.begin(), end), r_offset + offset); +boost::optional OffsetVfsFile::ReadByte(size_t r_offset) const { + if (r_offset < size) + return file->ReadByte(offset + r_offset); + + return boost::none; +} + +std::vector OffsetVfsFile::ReadBytes(size_t r_size, size_t r_offset) const { + return file->ReadBytes(TrimToFit(r_size, r_offset), offset + r_offset); +} + +std::vector 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 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 diff --git a/src/core/file_sys/vfs_offset.h b/src/core/file_sys/vfs_offset.h index 1d30b41e06..58d59448ea 100644 --- a/src/core/file_sys/vfs_offset.h +++ b/src/core/file_sys/vfs_offset.h @@ -3,30 +3,36 @@ // 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&& file, u64 offset, u64 size); + OffsetVfsFile(std::unique_ptr&& 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 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 ReadByte(size_t offset) const override; + std::vector ReadBytes(size_t size, size_t offset) const override; + std::vector ReadAllBytes() const override; + bool WriteByte(u8 data, size_t offset) override; + size_t WriteBytes(std::vector 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 GetContainingDirectory() override; - bool IsWritable() override; - bool IsReadable() override; - std::vector ReadBytes(u64 offset, u64 length) override; - u64 WriteBytes(const std::vector& data, u64 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 file; - u64 offset; - u64 size; + size_t offset; + size_t size; }; } // namespace FileSys diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index 1a703d3848..a592d1f59b 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp @@ -2,160 +2,128 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "common/common_paths.h" #include "common/logging/log.h" #include "core/file_sys/vfs_real.h" namespace FileSys { -RealVfsFile::RealVfsFile(const std::string& path, const char openmode[]) - : backing(path, openmode), path(path), mode(openmode) {} - -bool RealVfsFile::IsReady() { - return backing.IsOpen(); +static const char* PermissionsToCharArray(std::filesystem::perms perms) { + std::string out; + if ((perms & std::filesystem::perms::owner_read) != std::filesystem::perms::none) + out += "r"; + if ((perms & std::filesystem::perms::owner_write) != std::filesystem::perms::none) + out += "w"; + return out.c_str(); } -bool RealVfsFile::IsGood() { - return backing.IsGood(); +RealVfsFile::RealVfsFile(const std::filesystem::path& path_, std::filesystem::perms perms_) + : backing(path_.string(), PermissionsToCharArray(perms_)), path(path_), perms(perms_) {} + +std::string RealVfsFile::GetName() const { + return path.filename().string(); } -void RealVfsFile::ResetState() { - 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() { +size_t RealVfsFile::GetSize() const { return backing.GetSize(); } -bool RealVfsFile::Resize(u64 new_size) { +bool RealVfsFile::Resize(size_t new_size) { return backing.Resize(new_size); } -std::shared_ptr RealVfsFile::GetContainingDirectory() { - std::string part_path, name, extention; - Common::SplitPath(path, &part_path, &name, &extention); - return std::make_shared(part_path, mode.c_str()); +std::shared_ptr RealVfsFile::GetContainingDirectory() const { + return std::make_shared(path.parent_path(), perms); } -bool RealVfsFile::IsWritable() { - return mode.find('w') != std::string::npos; +bool RealVfsFile::IsWritable() const { + return (perms & std::filesystem::perms::owner_write) != std::filesystem::perms::none; } -bool RealVfsFile::IsReadable() { - return mode.find('r') != std::string::npos; +bool RealVfsFile::IsReadable() const { + return (perms & std::filesystem::perms::owner_read) != std::filesystem::perms::none; } -std::vector RealVfsFile::ReadBytes(u64 offset, u64 length) { - backing.Seek(offset, SEEK_SET); - std::vector out(length); - backing.ReadBytes(out.data(), length); - return out; +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); } -u64 RealVfsFile::WriteBytes(const std::vector& data, u64 offset) { - backing.Seek(offset, SEEK_SET); - return backing.WriteBytes(data.data(), data.size()); +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) { - auto out = FileUtil::Rename(GetName(), name); - std::string part_path, o_name, extention; - Common::SplitPath(path, &part_path, &o_name, &extention); - backing = FileUtil::IOFile(part_path + name, mode.c_str()); + const auto out = FileUtil::Rename(GetName(), name); + path = path.parent_path() / name; + backing = FileUtil::IOFile(path.string(), PermissionsToCharArray(perms)); return out; } -RealVfsDirectory::RealVfsDirectory(const std::string& path, const char openmode[]) - : path(path[path.size() - 1] == DIR_SEP_CHR ? path.substr(0, path.size() - 1) : path) { - FileUtil::FSTEntry entry; - if (0 != FileUtil::ScanDirectoryTree(path, entry)) - NGLOG_CRITICAL(Service_FS, "Failure to initialize file."); - for (FileUtil::FSTEntry child : entry.children) { - if (child.isDirectory) - subdirectories.emplace_back( - std::make_shared(child.physicalName, mode.c_str())); - else - files.emplace_back(std::make_shared(child.physicalName, mode.c_str())); +RealVfsDirectory::RealVfsDirectory(const std::filesystem::path& path_, + std::filesystem::perms perms_) + : path(path_), perms(perms_) { + for (const auto& entry : std::filesystem::directory_iterator(path)) { + if (std::filesystem::is_directory(entry.path())) + subdirectories.emplace_back(std::make_shared(entry.path(), perms)); + else if (std::filesystem::is_regular_file(entry.path())) + files.emplace_back(std::make_shared(entry.path(), perms)); } } -bool RealVfsDirectory::IsReady() { - return FileUtil::IsDirectory(path); -} - -bool RealVfsDirectory::IsGood() { - return FileUtil::IsDirectory(path); -} - -void RealVfsDirectory::ResetState() {} - -std::vector> RealVfsDirectory::GetFiles() { +std::vector> RealVfsDirectory::GetFiles() const { return std::vector>(files); } -std::vector> RealVfsDirectory::GetSubdirectories() { +std::vector> RealVfsDirectory::GetSubdirectories() const { return std::vector>(subdirectories); } -bool RealVfsDirectory::IsWritable() { - return mode.find('w') != std::string::npos; +bool RealVfsDirectory::IsWritable() const { + return (perms & std::filesystem::perms::owner_write) != std::filesystem::perms::none; } -bool RealVfsDirectory::IsReadable() { - return mode.find('r') != std::string::npos; +bool RealVfsDirectory::IsReadable() const { + return (perms & std::filesystem::perms::owner_read) != std::filesystem::perms::none; } -bool RealVfsDirectory::IsRoot() { - return path.empty() || (path.size() == 2 && path[1] == ':'); +std::string RealVfsDirectory::GetName() const { + return path.filename().string(); } -std::string RealVfsDirectory::GetName() { - size_t last = path.rfind(DIR_SEP_CHR); - return path.substr(last + 1); -} - -std::shared_ptr 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) +std::shared_ptr RealVfsDirectory::GetParentDirectory() const { + if (path.parent_path() == path.root_path()) return nullptr; - return std::make_shared(path.substr(0, last), mode.c_str()); + return std::make_shared(path.parent_path(), perms); } std::shared_ptr RealVfsDirectory::CreateSubdirectory(const std::string& name) { - FileUtil::CreateDir(path + DIR_SEP + name); - subdirectories.emplace_back( - std::make_shared(path + DIR_SEP + name, mode.c_str())); - return subdirectories[subdirectories.size() - 1]; + if (!FileUtil::CreateDir((path / name).string())) + return nullptr; + subdirectories.emplace_back(std::make_shared(path / name, perms)); + return subdirectories.back(); } std::shared_ptr RealVfsDirectory::CreateFile(const std::string& name) { - FileUtil::CreateEmptyFile(path + DIR_SEP + name); - files.emplace_back(std::make_shared(path + DIR_SEP + name, mode.c_str())); - return files[files.size() - 1]; + if (!FileUtil::CreateEmptyFile((path / name).string())) + return nullptr; + files.emplace_back(std::make_shared(path / name, perms)); + return files.back(); } 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) { - return FileUtil::Delete(path + DIR_SEP + name); + return FileUtil::Delete((path / name).string()); } bool RealVfsDirectory::Rename(const std::string& name) { - std::string part, o_name, extention; - Common::SplitPath(name, &part, &o_name, &extention); - return FileUtil::Rename(path, part + DIR_SEP + name); + return FileUtil::Rename(path.string(), (path / name).string()); } } // namespace FileSys diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h index bb81ed6845..63c285ad5a 100644 --- a/src/core/file_sys/vfs_real.h +++ b/src/core/file_sys/vfs_real.h @@ -3,46 +3,42 @@ // Refer to the license.txt file included. #pragma once + +#include #include "common/file_util.h" #include "core/file_sys/vfs.h" namespace FileSys { 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; - bool IsGood() override; - void ResetState() override; - std::string GetName() override; - u64 GetSize() override; - bool Resize(u64 new_size) override; - std::shared_ptr GetContainingDirectory() override; - bool IsWritable() override; - bool IsReadable() override; - std::vector ReadBytes(u64 offset, u64 length) override; - u64 WriteBytes(const std::vector& data, u64 offset) override; + std::string GetName() const override; + size_t GetSize() const override; + bool Resize(size_t new_size) override; + std::shared_ptr 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; - std::string path; - std::string mode; + std::filesystem::path path; + std::filesystem::perms perms; }; 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; - bool IsGood() override; - void ResetState() override; - std::vector> GetFiles() override; - std::vector> GetSubdirectories() override; - bool IsWritable() override; - bool IsReadable() override; - bool IsRoot() override; - std::string GetName() override; - std::shared_ptr GetParentDirectory() override; + std::vector> GetFiles() const override; + std::vector> GetSubdirectories() const override; + bool IsWritable() const override; + bool IsReadable() const override; + bool IsRoot() const override; + std::string GetName() const override; + std::shared_ptr GetParentDirectory() const override; std::shared_ptr CreateSubdirectory(const std::string& name) override; std::shared_ptr CreateFile(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; private: - std::string path; - std::string mode; + std::filesystem::path path; + std::filesystem::perms perms; std::vector> files; std::vector> subdirectories; };