diff --git a/Makefile b/Makefile index 7fe39351..7a616fec 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ include $(DEVKITPRO)/libnx/switch_rules # INCLUDES is a list of directories containing header files #--------------------------------------------------------------------------------- TARGET := $(notdir $(CURDIR)) -SOURCES := source source/ams source/hos source/result source/os source/os/impl source/dd source/sf source/sf/cmif source/sf/hipc source/dmnt source/spl source/spl/smc source/updater source/patcher source/map source/rnd source/util source/sm source/cfg source/pm source/hid source/ldr source/kvdb source/settings source/boot2 +SOURCES := source source/ams source/hos source/result source/os source/os/impl source/dd source/fs source/sf source/sf/cmif source/sf/hipc source/dmnt source/spl source/spl/smc source/updater source/patcher source/map source/rnd source/util source/sm source/cfg source/pm source/hid source/ldr source/kvdb source/settings source/boot2 DATA := data INCLUDES := include diff --git a/include/stratosphere/fs.hpp b/include/stratosphere/fs.hpp index d1347e3a..08a38d89 100644 --- a/include/stratosphere/fs.hpp +++ b/include/stratosphere/fs.hpp @@ -22,4 +22,5 @@ #include "fs/fs_remote_filesystem.hpp" #include "fs/fs_istorage.hpp" #include "fs/fs_remote_storage.hpp" +#include "fs/fs_file_storage.hpp" #include "fs/fs_query_range.hpp" diff --git a/include/stratosphere/fs/fs_file_storage.hpp b/include/stratosphere/fs/fs_file_storage.hpp new file mode 100644 index 00000000..892d3d3b --- /dev/null +++ b/include/stratosphere/fs/fs_file_storage.hpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "fs_common.hpp" +#include "fs_istorage.hpp" +#include "fsa/fs_ifile.hpp" + +namespace ams::fs { + + class FileStorage : public IStorage { + private: + static constexpr s64 InvalidSize = -1; + private: + std::unique_ptr unique_file; + std::shared_ptr shared_file; + fsa::IFile *base_file; + s64 size; + public: + FileStorage(fsa::IFile *f) : unique_file(f), size(InvalidSize) { + this->base_file = this->unique_file.get(); + } + + FileStorage(std::unique_ptr f) : unique_file(std::move(f)), size(InvalidSize) { + this->base_file = this->unique_file.get(); + } + + FileStorage(std::shared_ptr f) : shared_file(f), size(InvalidSize) { + this->base_file = this->shared_file.get(); + } + + virtual ~FileStorage() { /* ... */ } + 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/source/fs/fs_file_storage.cpp b/source/fs/fs_file_storage.cpp new file mode 100644 index 00000000..cfb05516 --- /dev/null +++ b/source/fs/fs_file_storage.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2018-2019 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +namespace ams::fs { + + Result FileStorage::UpdateSize() { + R_UNLESS(this->size == InvalidSize, ResultSuccess()); + return this->base_file->GetSize(&this->size); + } + + Result FileStorage::Read(s64 offset, void *buffer, size_t size) { + /* Immediately succeed if there's nothing to read. */ + R_UNLESS(size > 0, ResultSuccess()); + + /* 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()); + + size_t read_size; + return this->base_file->Read(&read_size, offset, buffer, size); + } + + Result FileStorage::Write(s64 offset, const void *buffer, size_t size) { + /* Immediately succeed if there's nothing to write. */ + R_UNLESS(size > 0, ResultSuccess()); + + /* 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 this->base_file->Write(offset, buffer, size, fs::WriteOption()); + } + + Result FileStorage::Flush() { + return this->base_file->Flush(); + } + + Result FileStorage::GetSize(s64 *out_size) { + R_TRY(this->UpdateSize()); + *out_size = this->size; + return ResultSuccess(); + } + + Result FileStorage::SetSize(s64 size) { + this->size = InvalidSize; + return this->base_file->SetSize(size); + } + + Result FileStorage::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::InvalidateCache: + case OperationId::QueryRange: + if (size == 0) { + if (op_id == OperationId::QueryRange) { + R_UNLESS(dst != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(dst_size == sizeof(QueryRangeInfo), fs::ResultInvalidSize()); + reinterpret_cast(dst)->Clear(); + } + return ResultSuccess(); + } + R_TRY(this->UpdateSize()); + R_UNLESS(IStorage::IsOffsetAndSizeValid(offset, size), fs::ResultOutOfRange()); + return this->base_file->OperateRange(dst, dst_size, op_id, offset, size, src, src_size); + default: + return fs::ResultUnsupportedOperation(); + } + } + +}