diff --git a/fusee/program/source/fs/fusee_fs_file_storage.cpp b/fusee/program/source/fs/fusee_fs_file_storage.cpp index a0a6eed5f..4de557c4f 100644 --- a/fusee/program/source/fs/fusee_fs_file_storage.cpp +++ b/fusee/program/source/fs/fusee_fs_file_storage.cpp @@ -34,7 +34,7 @@ namespace ams::fs { R_TRY(this->UpdateSize()); /* Ensure our access is valid. */ - R_UNLESS(IStorage::CheckAccessRange(offset, size, m_size), fs::ResultOutOfRange()); + R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); return ReadFile(m_handle, offset, buffer, size, fs::ReadOption()); } @@ -50,7 +50,7 @@ namespace ams::fs { R_TRY(this->UpdateSize()); /* Ensure our access is valid. */ - R_UNLESS(IStorage::CheckAccessRange(offset, size, m_size), fs::ResultOutOfRange()); + R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); return WriteFile(m_handle, offset, buffer, size, fs::WriteOption()); } diff --git a/fusee/program/source/fs/fusee_fs_storage.hpp b/fusee/program/source/fs/fusee_fs_storage.hpp index 8b44c42ef..58f8693ea 100644 --- a/fusee/program/source/fs/fusee_fs_storage.hpp +++ b/fusee/program/source/fs/fusee_fs_storage.hpp @@ -31,25 +31,38 @@ namespace ams::fs { virtual Result GetSize(s64 *out) = 0; public: - static inline bool CheckAccessRange(s64 offset, s64 size, s64 total_size) { - return offset >= 0 && - size >= 0 && - size <= total_size && - offset <= (total_size - size); + static inline Result CheckAccessRange(s64 offset, s64 size, s64 total_size) { + R_UNLESS(offset >= 0, fs::ResultInvalidOffset()); + R_UNLESS(size >= 0, fs::ResultInvalidSize()); + R_UNLESS(util::CanAddWithoutOverflow(offset, size), fs::ResultOutOfRange()); + R_UNLESS(offset + size <= total_size, fs::ResultOutOfRange()); + R_SUCCEED(); } - static inline bool CheckAccessRange(s64 offset, size_t size, s64 total_size) { - return CheckAccessRange(offset, static_cast(size), total_size); + static ALWAYS_INLINE Result CheckAccessRange(s64 offset, size_t size, s64 total_size) { + R_RETURN(CheckAccessRange(offset, static_cast(size), total_size)); } - static inline bool CheckOffsetAndSize(s64 offset, s64 size) { - return offset >= 0 && - size >= 0 && - offset <= (offset + size); + static inline Result CheckOffsetAndSize(s64 offset, s64 size) { + R_UNLESS(offset >= 0, fs::ResultInvalidOffset()); + R_UNLESS(size >= 0, fs::ResultInvalidSize()); + R_UNLESS(util::CanAddWithoutOverflow(offset, size), fs::ResultOutOfRange()); + R_SUCCEED(); } - static inline bool CheckOffsetAndSize(s64 offset, size_t size) { - return CheckOffsetAndSize(offset, static_cast(size)); + static ALWAYS_INLINE Result CheckOffsetAndSize(s64 offset, size_t size) { + R_RETURN(CheckOffsetAndSize(offset, static_cast(size))); + } + + static inline Result CheckOffsetAndSizeWithResult(s64 offset, s64 size, Result fail_result) { + R_TRY_CATCH(CheckOffsetAndSize(offset, size)) { + R_CONVERT_ALL(fail_result); + } R_END_TRY_CATCH; + R_SUCCEED(); + } + + static ALWAYS_INLINE Result CheckOffsetAndSizeWithResult(s64 offset, size_t size, Result fail_result) { + R_RETURN(CheckOffsetAndSizeWithResult(offset, static_cast(size), fail_result)); } }; @@ -93,8 +106,8 @@ namespace ams::fs { R_SUCCEED_IF(size == 0); /* Validate arguments and read. */ - R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); - R_UNLESS(IStorage::CheckAccessRange(offset, size, m_size), fs::ResultOutOfRange()); + R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); + R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); return m_storage.Read(m_offset + offset, buffer, size); } @@ -103,8 +116,8 @@ namespace ams::fs { R_SUCCEED_IF(size == 0); /* Validate arguments and write. */ - R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); - R_UNLESS(IStorage::CheckAccessRange(offset, size, m_size), fs::ResultOutOfRange()); + R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); + R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); return m_storage.Write(m_offset + offset, buffer, size); } diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_istorage.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_istorage.hpp index cd96b9afb..a9c39c3c2 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_istorage.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_istorage.hpp @@ -20,7 +20,7 @@ namespace ams::fs { - /* ACCURATE_TO_VERSION: Unknown */ + /* ACCURATE_TO_VERSION: 14.3.0.0 */ class IStorage { public: virtual ~IStorage() { /* ... */ } @@ -38,28 +38,41 @@ 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) = 0; virtual Result OperateRange(OperationId op_id, s64 offset, s64 size) { - return this->OperateRange(nullptr, 0, op_id, offset, size, nullptr, 0); + R_RETURN(this->OperateRange(nullptr, 0, op_id, offset, size, nullptr, 0)); } public: - static inline bool CheckAccessRange(s64 offset, s64 size, s64 total_size) { - return offset >= 0 && - size >= 0 && - size <= total_size && - offset <= (total_size - size); + static inline Result CheckAccessRange(s64 offset, s64 size, s64 total_size) { + R_UNLESS(offset >= 0, fs::ResultInvalidOffset()); + R_UNLESS(size >= 0, fs::ResultInvalidSize()); + R_UNLESS(util::CanAddWithoutOverflow(offset, size), fs::ResultOutOfRange()); + R_UNLESS(offset + size <= total_size, fs::ResultOutOfRange()); + R_SUCCEED(); } - static inline bool CheckAccessRange(s64 offset, size_t size, s64 total_size) { - return CheckAccessRange(offset, static_cast(size), total_size); + static ALWAYS_INLINE Result CheckAccessRange(s64 offset, size_t size, s64 total_size) { + R_RETURN(CheckAccessRange(offset, static_cast(size), total_size)); } - static inline bool CheckOffsetAndSize(s64 offset, s64 size) { - return offset >= 0 && - size >= 0 && - offset <= (offset + size); + static inline Result CheckOffsetAndSize(s64 offset, s64 size) { + R_UNLESS(offset >= 0, fs::ResultInvalidOffset()); + R_UNLESS(size >= 0, fs::ResultInvalidSize()); + R_UNLESS(util::CanAddWithoutOverflow(offset, size), fs::ResultOutOfRange()); + R_SUCCEED(); } - static inline bool CheckOffsetAndSize(s64 offset, size_t size) { - return CheckOffsetAndSize(offset, static_cast(size)); + static ALWAYS_INLINE Result CheckOffsetAndSize(s64 offset, size_t size) { + R_RETURN(CheckOffsetAndSize(offset, static_cast(size))); + } + + static inline Result CheckOffsetAndSizeWithResult(s64 offset, s64 size, Result fail_result) { + R_TRY_CATCH(CheckOffsetAndSize(offset, size)) { + R_CONVERT_ALL(fail_result); + } R_END_TRY_CATCH; + R_SUCCEED(); + } + + static ALWAYS_INLINE Result CheckOffsetAndSizeWithResult(s64 offset, size_t size, Result fail_result) { + R_RETURN(CheckOffsetAndSizeWithResult(offset, static_cast(size), fail_result)); } }; diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_memory_storage.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_memory_storage.hpp index dc12f9d02..3a31f9422 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_memory_storage.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_memory_storage.hpp @@ -34,7 +34,7 @@ namespace ams::fs { /* Validate arguments. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); - R_UNLESS(IStorage::CheckAccessRange(offset, size, m_size), fs::ResultOutOfRange()); + R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); /* Copy from memory. */ std::memcpy(buffer, m_buf + offset, size); @@ -47,7 +47,7 @@ namespace ams::fs { /* Validate arguments. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); - R_UNLESS(IStorage::CheckAccessRange(offset, size, m_size), fs::ResultOutOfRange()); + R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); /* Copy to memory. */ std::memcpy(m_buf + offset, buffer, size); diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_substorage.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_substorage.hpp index d98a8e8ca..edfcca6a3 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_substorage.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_substorage.hpp @@ -75,28 +75,28 @@ namespace ams::fs { public: virtual Result Read(s64 offset, void *buffer, size_t size) override { /* Ensure we're initialized. */ - R_UNLESS(this->IsValid(), fs::ResultNotInitialized()); + R_UNLESS(this->IsValid(), fs::ResultNotInitialized()); /* Succeed immediately on zero-sized operation. */ R_SUCCEED_IF(size == 0); /* Validate arguments and read. */ - R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); - R_UNLESS(IStorage::CheckAccessRange(offset, size, m_size), fs::ResultOutOfRange()); + R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); + R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); return m_base_storage->Read(m_offset + offset, buffer, size); } virtual Result Write(s64 offset, const void *buffer, size_t size) override{ /* Ensure we're initialized. */ - R_UNLESS(this->IsValid(), fs::ResultNotInitialized()); + R_UNLESS(this->IsValid(), fs::ResultNotInitialized()); /* Succeed immediately on zero-sized operation. */ R_SUCCEED_IF(size == 0); /* Validate arguments and write. */ - R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); - R_UNLESS(IStorage::CheckAccessRange(offset, size, m_size), fs::ResultOutOfRange()); + R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); + R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); return m_base_storage->Write(m_offset + offset, buffer, size); } @@ -109,7 +109,8 @@ namespace ams::fs { /* Ensure we're initialized and validate arguments. */ R_UNLESS(this->IsValid(), fs::ResultNotInitialized()); R_UNLESS(m_resizable, fs::ResultUnsupportedSetSizeForNotResizableSubStorage()); - R_UNLESS(IStorage::CheckOffsetAndSize(m_offset, size), fs::ResultInvalidSize()); + + R_TRY(IStorage::CheckOffsetAndSize(m_offset, size)); /* Ensure that we're allowed to set size. */ s64 cur_size; @@ -135,12 +136,17 @@ namespace ams::fs { /* Ensure we're initialized. */ R_UNLESS(this->IsValid(), fs::ResultNotInitialized()); - /* Succeed immediately on zero-sized operation. */ - R_SUCCEED_IF(size == 0); + /* If we're not invalidating, sanity check arguments. */ + if (op_id != fs::OperationId::Invalidate) { + /* Succeed immediately on zero-sized operation other than invalidate. */ + R_SUCCEED_IF(size == 0); - /* Validate arguments and operate. */ - R_UNLESS(IStorage::CheckOffsetAndSize(offset, size), fs::ResultOutOfRange()); - return m_base_storage->OperateRange(dst, dst_size, op_id, m_offset + offset, size, src, src_size); + /* Check access extents. */ + R_TRY(IStorage::CheckOffsetAndSize(offset, size)); + } + + /* Perform the operation. */ + R_RETURN(m_base_storage->OperateRange(dst, dst_size, op_id, m_offset + offset, size, src, src_size)); } using IStorage::OperateRange; diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_alignment_matching_storage.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_alignment_matching_storage.hpp index 9e53b3ada..b1d276579 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_alignment_matching_storage.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_alignment_matching_storage.hpp @@ -62,7 +62,7 @@ namespace ams::fssystem { s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); - R_UNLESS(fs::IStorage::CheckAccessRange(offset, size, bs_size), fs::ResultOutOfRange()); + R_TRY(fs::IStorage::CheckAccessRange(offset, size, bs_size)); return AlignmentMatchingStorageImpl::Read(m_base_storage, work_buf, sizeof(work_buf), DataAlign, BufferAlign, offset, static_cast(buffer), size); } @@ -80,7 +80,7 @@ namespace ams::fssystem { s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); - R_UNLESS(fs::IStorage::CheckAccessRange(offset, size, bs_size), fs::ResultOutOfRange()); + R_TRY(fs::IStorage::CheckAccessRange(offset, size, bs_size)); return AlignmentMatchingStorageImpl::Write(m_base_storage, work_buf, sizeof(work_buf), DataAlign, BufferAlign, offset, static_cast(buffer), size); } @@ -119,7 +119,7 @@ namespace ams::fssystem { /* Get the base storage size. */ s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); - R_UNLESS(fs::IStorage::CheckOffsetAndSize(offset, size), fs::ResultOutOfRange()); + R_TRY(fs::IStorage::CheckOffsetAndSize(offset, size)); /* Operate on the base storage. */ const auto valid_size = std::min(size, bs_size - offset); @@ -160,7 +160,7 @@ namespace ams::fssystem { s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); - R_UNLESS(fs::IStorage::CheckAccessRange(offset, size, bs_size), fs::ResultOutOfRange()); + R_TRY(fs::IStorage::CheckAccessRange(offset, size, bs_size)); /* Allocate a pooled buffer. */ PooledBuffer pooled_buffer; @@ -178,7 +178,7 @@ namespace ams::fssystem { s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); - R_UNLESS(fs::IStorage::CheckAccessRange(offset, size, bs_size), fs::ResultOutOfRange()); + R_TRY(fs::IStorage::CheckAccessRange(offset, size, bs_size)); /* Allocate a pooled buffer. */ PooledBuffer pooled_buffer; @@ -221,7 +221,7 @@ namespace ams::fssystem { /* Get the base storage size. */ s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); - R_UNLESS(fs::IStorage::CheckOffsetAndSize(offset, size), fs::ResultOutOfRange()); + R_TRY(fs::IStorage::CheckOffsetAndSize(offset, size)); /* Operate on the base storage. */ const auto valid_size = std::min(size, bs_size - offset); @@ -268,7 +268,7 @@ namespace ams::fssystem { s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); - R_UNLESS(fs::IStorage::CheckAccessRange(offset, size, bs_size), fs::ResultOutOfRange()); + R_TRY(fs::IStorage::CheckAccessRange(offset, size, bs_size)); /* Allocate a pooled buffer. */ PooledBuffer pooled_buffer(m_data_align, m_data_align); @@ -308,7 +308,7 @@ namespace ams::fssystem { /* Get the base storage size. */ s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); - R_UNLESS(fs::IStorage::CheckOffsetAndSize(offset, size), fs::ResultOutOfRange()); + R_TRY(fs::IStorage::CheckOffsetAndSize(offset, size)); /* Operate on the base storage. */ const auto valid_size = std::min(size, bs_size - offset); diff --git a/libraries/libstratosphere/source/fs/common/fs_file_storage.cpp b/libraries/libstratosphere/source/fs/common/fs_file_storage.cpp index 84d60518d..904969d17 100644 --- a/libraries/libstratosphere/source/fs/common/fs_file_storage.cpp +++ b/libraries/libstratosphere/source/fs/common/fs_file_storage.cpp @@ -33,7 +33,7 @@ namespace ams::fs { R_TRY(this->UpdateSize()); /* Ensure our access is valid. */ - R_UNLESS(IStorage::CheckAccessRange(offset, size, m_size), fs::ResultOutOfRange()); + R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); size_t read_size; return m_base_file->Read(std::addressof(read_size), offset, buffer, size); @@ -50,7 +50,7 @@ namespace ams::fs { R_TRY(this->UpdateSize()); /* Ensure our access is valid. */ - R_UNLESS(IStorage::CheckAccessRange(offset, size, m_size), fs::ResultOutOfRange()); + R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); return m_base_file->Write(offset, buffer, size, fs::WriteOption()); } @@ -73,20 +73,21 @@ namespace ams::fs { 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::Invalidate: + R_RETURN(m_base_file->OperateRange(OperationId::Invalidate, offset, size)); 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_UNLESS(dst != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(dst_size == sizeof(QueryRangeInfo), fs::ResultInvalidSize()); + reinterpret_cast(dst)->Clear(); + R_SUCCEED(); } + R_TRY(this->UpdateSize()); - R_UNLESS(IStorage::CheckOffsetAndSize(offset, size), fs::ResultOutOfRange()); - return m_base_file->OperateRange(dst, dst_size, op_id, offset, size, src, src_size); + R_TRY(IStorage::CheckOffsetAndSize(offset, size)); + + R_RETURN(m_base_file->OperateRange(dst, dst_size, op_id, offset, size, src, src_size)); default: - return fs::ResultUnsupportedOperateRangeForFileStorage(); + R_THROW(fs::ResultUnsupportedOperateRangeForFileStorage()); } } @@ -121,7 +122,7 @@ namespace ams::fs { R_TRY(this->UpdateSize()); /* Ensure our access is valid. */ - R_UNLESS(IStorage::CheckAccessRange(offset, size, m_size), fs::ResultOutOfRange()); + R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); return ReadFile(m_handle, offset, buffer, size, fs::ReadOption()); } @@ -140,7 +141,7 @@ namespace ams::fs { R_TRY(this->UpdateSize()); /* Ensure our access is valid. */ - R_UNLESS(IStorage::CheckAccessRange(offset, size, m_size), fs::ResultOutOfRange()); + R_TRY(IStorage::CheckAccessRange(offset, size, m_size)); return WriteFile(m_handle, offset, buffer, size, fs::WriteOption()); } diff --git a/libraries/libstratosphere/source/fssystem/fssystem_alignment_matching_storage_impl.cpp b/libraries/libstratosphere/source/fssystem/fssystem_alignment_matching_storage_impl.cpp index 37306a6af..95d1c9bba 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_alignment_matching_storage_impl.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_alignment_matching_storage_impl.cpp @@ -199,7 +199,7 @@ namespace ams::fssystem { s64 bs_size = 0; R_TRY(this->GetSize(std::addressof(bs_size))); - R_UNLESS(fs::IStorage::CheckAccessRange(offset, size, bs_size), fs::ResultOutOfRange()); + R_TRY(fs::IStorage::CheckAccessRange(offset, size, bs_size)); /* Determine extents. */ const auto offset_end = offset + static_cast(size); diff --git a/libraries/libstratosphere/source/fssystem/fssystem_integrity_verification_storage.cpp b/libraries/libstratosphere/source/fssystem/fssystem_integrity_verification_storage.cpp index 385aeabfa..c60617cb9 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_integrity_verification_storage.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_integrity_verification_storage.cpp @@ -92,7 +92,7 @@ namespace ams::fssystem { R_UNLESS(offset <= data_size, fs::ResultInvalidOffset()); /* Validate the access range. */ - R_UNLESS(IStorage::CheckAccessRange(offset, size, util::AlignUp(data_size, static_cast(m_verification_block_size))), fs::ResultOutOfRange()); + R_TRY(IStorage::CheckAccessRange(offset, size, util::AlignUp(data_size, static_cast(m_verification_block_size)))); /* Determine the read extents. */ size_t read_size = size; @@ -174,7 +174,9 @@ namespace ams::fssystem { /* Validate arguments. */ R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument()); - R_UNLESS(IStorage::CheckOffsetAndSize(offset, size), fs::ResultInvalidOffset()); + + /* Check the offset/size. */ + R_TRY(IStorage::CheckOffsetAndSize(offset, size)); /* Validate the offset. */ s64 data_size; @@ -182,7 +184,7 @@ namespace ams::fssystem { R_UNLESS(offset < data_size, fs::ResultInvalidOffset()); /* Validate the access range. */ - R_UNLESS(IStorage::CheckAccessRange(offset, size, util::AlignUp(data_size, static_cast(m_verification_block_size))), fs::ResultOutOfRange()); + R_TRY(IStorage::CheckAccessRange(offset, size, util::AlignUp(data_size, static_cast(m_verification_block_size)))); /* Validate preconditions. */ AMS_ASSERT(util::IsAligned(offset, m_verification_block_size));