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);