diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_file_storage.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_file_storage.hpp index 950f6d1df..2ef9cdf11 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_file_storage.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_file_storage.hpp @@ -14,13 +14,14 @@ * along with this program. If not, see . */ #pragma once -#include "fs_common.hpp" -#include "fs_istorage.hpp" -#include "fsa/fs_ifile.hpp" +#include +#include +#include +#include namespace ams::fs { - class FileStorage : public IStorage { + class FileStorage : public IStorage, public impl::Newable { private: static constexpr s64 InvalidSize = -1; private: @@ -53,4 +54,32 @@ namespace ams::fs { virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override; }; + class FileHandleStorage : public IStorage, public impl::Newable { + private: + static constexpr s64 InvalidSize = -1; + private: + FileHandle handle; + bool close_file; + s64 size; + os::Mutex mutex; + public: + constexpr explicit FileHandleStorage(FileHandle handle, bool close_file) : handle(handle), close_file(close_file), size(InvalidSize), mutex() { /* ... */ } + constexpr explicit FileHandleStorage(FileHandle handle) : FileHandleStorage(handle, false) { /* ... */ } + + virtual ~FileHandleStorage() override { + if (this->close_file) { + CloseFile(this->handle); + } + } + protected: + Result UpdateSize(); + public: + virtual Result Read(s64 offset, void *buffer, size_t size) override; + virtual Result Write(s64 offset, const void *buffer, size_t size) override; + virtual Result Flush() override; + virtual Result GetSize(s64 *out_size) override; + virtual Result SetSize(s64 size) override; + virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override; + }; + } diff --git a/libraries/libstratosphere/source/fs/fs_file_storage.cpp b/libraries/libstratosphere/source/fs/fs_file_storage.cpp index 88105baab..f7ee4c14c 100644 --- a/libraries/libstratosphere/source/fs/fs_file_storage.cpp +++ b/libraries/libstratosphere/source/fs/fs_file_storage.cpp @@ -90,4 +90,75 @@ namespace ams::fs { } } + Result FileHandleStorage::UpdateSize() { + R_SUCCEED_IF(this->size != InvalidSize); + return GetFileSize(std::addressof(this->size), this->handle); + } + + Result FileHandleStorage::Read(s64 offset, void *buffer, size_t size) { + /* Lock the mutex. */ + std::scoped_lock lk(this->mutex); + + /* Immediately succeed if there's nothing to read. */ + R_SUCCEED_IF(size == 0); + + /* Validate buffer. */ + R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); + + /* Ensure our size is valid. */ + R_TRY(this->UpdateSize()); + + /* Ensure our access is valid. */ + R_UNLESS(IStorage::IsRangeValid(offset, size, this->size), fs::ResultOutOfRange()); + + return ReadFile(this->handle, offset, buffer, size, fs::ReadOption()); + } + + Result FileHandleStorage::Write(s64 offset, const void *buffer, size_t size) { + /* Lock the mutex. */ + std::scoped_lock lk(this->mutex); + + /* Immediately succeed if there's nothing to write. */ + R_SUCCEED_IF(size == 0); + + /* Validate buffer. */ + R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); + + /* Ensure our size is valid. */ + R_TRY(this->UpdateSize()); + + /* Ensure our access is valid. */ + R_UNLESS(IStorage::IsRangeValid(offset, size, this->size), fs::ResultOutOfRange()); + + return WriteFile(this->handle, offset, buffer, size, fs::WriteOption()); + } + + Result FileHandleStorage::Flush() { + return FlushFile(this->handle); + } + + Result FileHandleStorage::GetSize(s64 *out_size) { + R_TRY(this->UpdateSize()); + *out_size = this->size; + return ResultSuccess(); + } + + Result FileHandleStorage::SetSize(s64 size) { + this->size = InvalidSize; + return SetFileSize(this->handle, size); + } + + Result FileHandleStorage::OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) { + switch (op_id) { + case OperationId::QueryRange: + /* Validate buffer and size. */ + R_UNLESS(dst != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(dst_size == sizeof(QueryRangeInfo), fs::ResultInvalidSize()); + + return QueryRange(static_cast(dst), this->handle, offset, size); + default: + return fs::ResultUnsupportedOperationInFileStorageB(); + } + } + } diff --git a/libraries/libvapours/include/vapours/results/fs_results.hpp b/libraries/libvapours/include/vapours/results/fs_results.hpp index acc581d62..8e323d794 100644 --- a/libraries/libvapours/include/vapours/results/fs_results.hpp +++ b/libraries/libvapours/include/vapours/results/fs_results.hpp @@ -254,6 +254,7 @@ namespace ams::fs { R_DEFINE_ERROR_RESULT(UnsupportedOperationInMemoryStorageA, 6304); R_DEFINE_ERROR_RESULT(UnsupportedOperationInMemoryStorageB, 6305); R_DEFINE_ERROR_RESULT(UnsupportedOperationInFileStorageA, 6306); + R_DEFINE_ERROR_RESULT(UnsupportedOperationInFileStorageB, 6307); R_DEFINE_ERROR_RESULT(UnsupportedOperationInFileServiceObjectAdapterA, 6362); R_DEFINE_ERROR_RESULT(UnsupportedOperationInRomFsFileSystemA, 6364); R_DEFINE_ERROR_RESULT(UnsupportedOperationInRomFsFileSystemB, 6365);