mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-06-03 08:08:39 -04:00
fs: revise NcaFileSystemDriver for latest semantics
This commit is contained in:
parent
ccf29a1302
commit
52296fc2dd
37 changed files with 1612 additions and 1026 deletions
|
@ -20,6 +20,7 @@
|
|||
|
||||
namespace ams::fssystem {
|
||||
|
||||
template<typename BasePointer>
|
||||
class AesCtrStorage : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable {
|
||||
NON_COPYABLE(AesCtrStorage);
|
||||
NON_MOVEABLE(AesCtrStorage);
|
||||
|
@ -28,13 +29,13 @@ namespace ams::fssystem {
|
|||
static constexpr size_t KeySize = crypto::Aes128CtrEncryptor::KeySize;
|
||||
static constexpr size_t IvSize = crypto::Aes128CtrEncryptor::IvSize;
|
||||
private:
|
||||
IStorage * const m_base_storage;
|
||||
BasePointer m_base_storage;
|
||||
char m_key[KeySize];
|
||||
char m_iv[IvSize];
|
||||
public:
|
||||
static void MakeIv(void *dst, size_t dst_size, u64 upper, s64 offset);
|
||||
public:
|
||||
AesCtrStorage(IStorage *base, const void *key, size_t key_size, const void *iv, size_t iv_size);
|
||||
AesCtrStorage(BasePointer base, const void *key, size_t key_size, const void *iv, size_t iv_size);
|
||||
|
||||
virtual Result Read(s64 offset, void *buffer, size_t size) override;
|
||||
virtual Result Write(s64 offset, const void *buffer, size_t size) override;
|
||||
|
@ -47,4 +48,7 @@ namespace ams::fssystem {
|
|||
virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override;
|
||||
};
|
||||
|
||||
using AesCtrStorageByPointer = AesCtrStorage<fs::IStorage *>;
|
||||
using AesCtrStorageBySharedPointer = AesCtrStorage<std::shared_ptr<fs::IStorage>>;
|
||||
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
namespace ams::fssystem {
|
||||
|
||||
template<typename BasePointer>
|
||||
class AesXtsStorage : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable {
|
||||
NON_COPYABLE(AesXtsStorage);
|
||||
NON_MOVEABLE(AesXtsStorage);
|
||||
|
@ -29,13 +30,15 @@ namespace ams::fssystem {
|
|||
static constexpr size_t KeySize = crypto::Aes128XtsEncryptor::KeySize;
|
||||
static constexpr size_t IvSize = crypto::Aes128XtsEncryptor::IvSize;
|
||||
private:
|
||||
IStorage * const m_base_storage;
|
||||
BasePointer m_base_storage;
|
||||
char m_key[2][KeySize];
|
||||
char m_iv[IvSize];
|
||||
const size_t m_block_size;
|
||||
os::SdkMutex m_mutex;
|
||||
public:
|
||||
AesXtsStorage(IStorage *base, const void *key1, const void *key2, size_t key_size, const void *iv, size_t iv_size, size_t block_size);
|
||||
static void MakeAesXtsIv(void *dst, size_t dst_size, s64 offset, size_t block_size);
|
||||
public:
|
||||
AesXtsStorage(BasePointer base, const void *key1, const void *key2, size_t key_size, const void *iv, size_t iv_size, size_t block_size);
|
||||
|
||||
virtual Result Read(s64 offset, void *buffer, size_t size) override;
|
||||
virtual Result Write(s64 offset, const void *buffer, size_t size) override;
|
||||
|
@ -48,4 +51,7 @@ namespace ams::fssystem {
|
|||
virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override;
|
||||
};
|
||||
|
||||
using AesXtsStorageByPointer = AesXtsStorage<fs::IStorage *>;
|
||||
using AesXtsStorageBySharedPointer = AesXtsStorage<std::shared_ptr<fs::IStorage>>;
|
||||
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ namespace ams::fssystem {
|
|||
/* ... */
|
||||
}
|
||||
|
||||
explicit AlignmentMatchingStorage(std::shared_ptr<fs::IStorage> bs) : m_shared_base_storage(bs), m_base_storage(m_shared_base_storage.get()), m_is_base_storage_size_dirty(true) {
|
||||
explicit AlignmentMatchingStorage(std::shared_ptr<fs::IStorage> bs) : m_shared_base_storage(std::move(bs)), m_base_storage(m_shared_base_storage.get()), m_is_base_storage_size_dirty(true) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
|
@ -109,25 +109,29 @@ namespace ams::fssystem {
|
|||
}
|
||||
|
||||
virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override {
|
||||
/* Succeed if zero size. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
if (op_id == fs::OperationId::Invalidate) {
|
||||
return m_base_storage->OperateRange(fs::OperationId::Invalidate, offset, size);
|
||||
} else {
|
||||
/* Succeed if zero size. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
/* 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());
|
||||
/* 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());
|
||||
|
||||
/* Operate on the base storage. */
|
||||
const auto valid_size = std::min(size, bs_size - offset);
|
||||
const auto aligned_offset = util::AlignDown(offset, DataAlign);
|
||||
const auto aligned_offset_end = util::AlignUp(offset + valid_size, DataAlign);
|
||||
const auto aligned_size = aligned_offset_end - aligned_offset;
|
||||
/* Operate on the base storage. */
|
||||
const auto valid_size = std::min(size, bs_size - offset);
|
||||
const auto aligned_offset = util::AlignDown(offset, DataAlign);
|
||||
const auto aligned_offset_end = util::AlignUp(offset + valid_size, DataAlign);
|
||||
const auto aligned_size = aligned_offset_end - aligned_offset;
|
||||
|
||||
return m_base_storage->OperateRange(dst, dst_size, op_id, aligned_offset, aligned_size, src, src_size);
|
||||
return m_base_storage->OperateRange(dst, dst_size, op_id, aligned_offset, aligned_size, src, src_size);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<size_t _BufferAlign>
|
||||
template<typename BaseStorageType, size_t _BufferAlign>
|
||||
class AlignmentMatchingStoragePooledBuffer : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable {
|
||||
NON_COPYABLE(AlignmentMatchingStoragePooledBuffer);
|
||||
NON_MOVEABLE(AlignmentMatchingStoragePooledBuffer);
|
||||
|
@ -136,12 +140,12 @@ namespace ams::fssystem {
|
|||
|
||||
static_assert(util::IsPowerOfTwo(BufferAlign));
|
||||
private:
|
||||
fs::IStorage * const m_base_storage;
|
||||
BaseStorageType m_base_storage;
|
||||
s64 m_base_storage_size;
|
||||
size_t m_data_align;
|
||||
bool m_is_base_storage_size_dirty;
|
||||
public:
|
||||
explicit AlignmentMatchingStoragePooledBuffer(fs::IStorage *bs, size_t da) : m_base_storage(bs), m_data_align(da), m_is_base_storage_size_dirty(true) {
|
||||
explicit AlignmentMatchingStoragePooledBuffer(BaseStorageType bs, size_t da) : m_base_storage(std::move(bs)), m_data_align(da), m_is_base_storage_size_dirty(true) {
|
||||
AMS_ASSERT(util::IsPowerOfTwo(da));
|
||||
}
|
||||
|
||||
|
@ -206,21 +210,25 @@ namespace ams::fssystem {
|
|||
}
|
||||
|
||||
virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override {
|
||||
/* Succeed if zero size. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
if (op_id == fs::OperationId::Invalidate) {
|
||||
return m_base_storage->OperateRange(fs::OperationId::Invalidate, offset, size);
|
||||
} else {
|
||||
/* Succeed if zero size. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
/* 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());
|
||||
/* 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());
|
||||
|
||||
/* Operate on the base storage. */
|
||||
const auto valid_size = std::min(size, bs_size - offset);
|
||||
const auto aligned_offset = util::AlignDown(offset, m_data_align);
|
||||
const auto aligned_offset_end = util::AlignUp(offset + valid_size, m_data_align);
|
||||
const auto aligned_size = aligned_offset_end - aligned_offset;
|
||||
/* Operate on the base storage. */
|
||||
const auto valid_size = std::min(size, bs_size - offset);
|
||||
const auto aligned_offset = util::AlignDown(offset, m_data_align);
|
||||
const auto aligned_offset_end = util::AlignUp(offset + valid_size, m_data_align);
|
||||
const auto aligned_size = aligned_offset_end - aligned_offset;
|
||||
|
||||
return m_base_storage->OperateRange(dst, dst_size, op_id, aligned_offset, aligned_size, src, src_size);
|
||||
return m_base_storage->OperateRange(dst, dst_size, op_id, aligned_offset, aligned_size, src, src_size);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -288,21 +296,25 @@ namespace ams::fssystem {
|
|||
}
|
||||
|
||||
virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override {
|
||||
/* Succeed if zero size. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
if (op_id == fs::OperationId::Invalidate) {
|
||||
return m_base_storage->OperateRange(fs::OperationId::Invalidate, offset, size);
|
||||
} else {
|
||||
/* Succeed if zero size. */
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
/* 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());
|
||||
/* 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());
|
||||
|
||||
/* Operate on the base storage. */
|
||||
const auto valid_size = std::min(size, bs_size - offset);
|
||||
const auto aligned_offset = util::AlignDown(offset, m_data_align);
|
||||
const auto aligned_offset_end = util::AlignUp(offset + valid_size, m_data_align);
|
||||
const auto aligned_size = aligned_offset_end - aligned_offset;
|
||||
/* Operate on the base storage. */
|
||||
const auto valid_size = std::min(size, bs_size - offset);
|
||||
const auto aligned_offset = util::AlignDown(offset, m_data_align);
|
||||
const auto aligned_offset_end = util::AlignUp(offset + valid_size, m_data_align);
|
||||
const auto aligned_size = aligned_offset_end - aligned_offset;
|
||||
|
||||
return m_base_storage->OperateRange(dst, dst_size, op_id, aligned_offset, aligned_size, src, src_size);
|
||||
return m_base_storage->OperateRange(dst, dst_size, op_id, aligned_offset, aligned_size, src, src_size);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -23,6 +23,14 @@ namespace ams::fssystem {
|
|||
public:
|
||||
static Result Read(fs::IStorage *base_storage, char *work_buf, size_t work_buf_size, size_t data_alignment, size_t buffer_alignment, s64 offset, char *buffer, size_t size);
|
||||
static Result Write(fs::IStorage *base_storage, char *work_buf, size_t work_buf_size, size_t data_alignment, size_t buffer_alignment, s64 offset, const char *buffer, size_t size);
|
||||
|
||||
static Result Read(std::shared_ptr<fs::IStorage> &base_storage, char *work_buf, size_t work_buf_size, size_t data_alignment, size_t buffer_alignment, s64 offset, char *buffer, size_t size) {
|
||||
return Read(base_storage.get(), work_buf, work_buf_size, data_alignment, buffer_alignment, offset, buffer, size);
|
||||
}
|
||||
|
||||
static Result Write(std::shared_ptr<fs::IStorage> &base_storage, char *work_buf, size_t work_buf_size, size_t data_alignment, size_t buffer_alignment, s64 offset, const char *buffer, size_t size) {
|
||||
return Write(base_storage.get(), work_buf, work_buf_size, data_alignment, buffer_alignment, offset, buffer, size);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
|
||||
namespace ams::fssystem {
|
||||
|
||||
class IAsynchronousAccessSplitter {
|
||||
public:
|
||||
static IAsynchronousAccessSplitter *GetDefaultAsynchronousAccessSplitter();
|
||||
public:
|
||||
constexpr IAsynchronousAccessSplitter() = default;
|
||||
constexpr virtual ~IAsynchronousAccessSplitter() { /* ... */ }
|
||||
public:
|
||||
Result QueryNextOffset(s64 *out, s64 start_offset, s64 end_offset, s64 access_size, s64 alignment_size);
|
||||
public:
|
||||
virtual Result QueryAppropriateOffset(s64 *out, s64 offset, s64 access_size, s64 alignment_size) = 0;
|
||||
virtual Result QueryInvocationCount(s64 *out, s64 start_offset, s64 end_offset, s64 access_size, s64 alignment_size);
|
||||
};
|
||||
|
||||
class DefaultAsynchronousAccessSplitter final : public IAsynchronousAccessSplitter {
|
||||
public:
|
||||
constexpr DefaultAsynchronousAccessSplitter() = default;
|
||||
public:
|
||||
virtual Result QueryAppropriateOffset(s64 *out, s64 offset, s64 access_size, s64 alignment_size) override {
|
||||
/* Align the access. */
|
||||
*out = util::AlignDown(offset + access_size, alignment_size);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
virtual Result QueryInvocationCount(s64 *out, s64 start_offset, s64 end_offset, s64 access_size, s64 alignment_size) override {
|
||||
/* Determine aligned access count. */
|
||||
*out = util::DivideUp(end_offset - util::AlignDown(start_offset, alignment_size), access_size);
|
||||
return ResultSuccess();
|
||||
}
|
||||
};
|
||||
|
||||
inline IAsynchronousAccessSplitter *IAsynchronousAccessSplitter::GetDefaultAsynchronousAccessSplitter() {
|
||||
static constinit DefaultAsynchronousAccessSplitter s_default_access_splitter;
|
||||
return std::addressof(s_default_access_splitter);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/fssystem/fssystem_asynchronous_access.hpp>
|
||||
#include <stratosphere/fssystem/fssystem_bucket_tree.hpp>
|
||||
#include <stratosphere/fssystem/fssystem_compression_common.hpp>
|
||||
|
||||
namespace ams::fssystem {
|
||||
|
||||
class CompressedStorage : public ::ams::fs::IStorage, public ::ams::fssystem::IAsynchronousAccessSplitter, public ::ams::fs::impl::Newable {
|
||||
NON_COPYABLE(CompressedStorage);
|
||||
NON_MOVEABLE(CompressedStorage);
|
||||
public:
|
||||
static constexpr size_t NodeSize = 16_KB;
|
||||
|
||||
using IAllocator = BucketTree::IAllocator;
|
||||
|
||||
struct Entry {
|
||||
s64 virt_offset;
|
||||
s64 phys_offset;
|
||||
CompressionType compression_type;
|
||||
s32 phys_size;
|
||||
|
||||
s64 GetPhysicalSize() const {
|
||||
return this->phys_size;
|
||||
}
|
||||
};
|
||||
static_assert(util::is_pod<Entry>::value);
|
||||
static_assert(sizeof(Entry) == 0x18);
|
||||
public:
|
||||
static constexpr s64 QueryNodeStorageSize(s32 entry_count) {
|
||||
return BucketTree::QueryNodeStorageSize(NodeSize, sizeof(Entry), entry_count);
|
||||
}
|
||||
|
||||
static constexpr s64 QueryEntryStorageSize(s32 entry_count) {
|
||||
return BucketTree::QueryEntryStorageSize(NodeSize, sizeof(Entry), entry_count);
|
||||
}
|
||||
private:
|
||||
/* TODO: CompressedStorageCore m_core; */
|
||||
/* TODO: CacheManager m_cache_manager; */
|
||||
public:
|
||||
CompressedStorage() { /* ... */ }
|
||||
virtual ~CompressedStorage() { this->Finalize(); }
|
||||
|
||||
Result Initialize(MemoryResource *bktr_allocator, IBufferManager *cache_allocator, fs::SubStorage data_storage, fs::SubStorage node_storage, fs::SubStorage entry_storage, s32 bktr_entry_count, size_t block_size_max, size_t continuous_reading_size_max, GetDecompressorFunction get_decompressor, size_t cache_size_0, size_t cache_size_1, s32 max_cache_entries);
|
||||
|
||||
void Finalize() {
|
||||
AMS_ABORT("TODO");
|
||||
/* m_cache_manager.Finalize(); */
|
||||
/* m_core.Finalize(); */
|
||||
}
|
||||
public:
|
||||
virtual Result QueryAppropriateOffset(s64 *out, s64 offset, s64 access_size, s64 alignment_size) override {
|
||||
AMS_ABORT("TODO");
|
||||
/* return m_core.QueryAppropriateOffsetForAsynchronousAccess(out, offset, access_size, alignment_size); */
|
||||
}
|
||||
public:
|
||||
virtual Result Read(s64 offset, void *buffer, size_t size) override;
|
||||
virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override;
|
||||
|
||||
virtual Result GetSize(s64 *out) override {
|
||||
AMS_ABORT("TODO");
|
||||
/* return m_core.GetSize(out); */
|
||||
}
|
||||
|
||||
virtual Result Flush() override {
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
virtual Result Write(s64 offset, const void *buffer, size_t size) override {
|
||||
AMS_UNUSED(offset, buffer, size);
|
||||
return fs::ResultUnsupportedOperationInCompressedStorageA();
|
||||
}
|
||||
|
||||
virtual Result SetSize(s64 size) override {
|
||||
AMS_UNUSED(size);
|
||||
/* NOTE: Is Nintendo returning the wrong result here? */
|
||||
return fs::ResultUnsupportedOperationInIndirectStorageB();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
|
||||
namespace ams::fssystem {
|
||||
|
||||
enum CompressionType {
|
||||
CompressionType_None = 0,
|
||||
CompressionType_1 = 1,
|
||||
CompressionType_2 = 2,
|
||||
CompressionType_Lz4 = 3,
|
||||
CompressionType_Unknown = 4,
|
||||
};
|
||||
|
||||
using DecompressorFunction = Result (*)(void *, size_t, const void *, size_t);
|
||||
using GetDecompressorFunction = DecompressorFunction (*)(CompressionType);
|
||||
|
||||
namespace CompressionTypeUtility {
|
||||
|
||||
constexpr bool IsBlockAlignmentRequired(CompressionType type) {
|
||||
return type != CompressionType_None && type != CompressionType_1;
|
||||
}
|
||||
|
||||
constexpr bool IsDataStorageAccessRequired(CompressionType type) {
|
||||
return type != CompressionType_1;
|
||||
}
|
||||
|
||||
constexpr bool IsRandomAccessible(CompressionType type) {
|
||||
return CompressionType_None;
|
||||
}
|
||||
|
||||
constexpr bool IsUnknownType(CompressionType type) {
|
||||
return type >= CompressionType_Unknown;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright (c) 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/fssystem/fssystem_nca_file_system_driver.hpp>
|
||||
|
||||
namespace ams::fssystem {
|
||||
|
||||
const ::ams::fssystem::NcaCompressionConfiguration *GetNcaCompressionConfiguration();
|
||||
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright (c) 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
|
||||
namespace ams::fssystem {
|
||||
|
||||
class IHash256Generator {
|
||||
public:
|
||||
static constexpr size_t HashSize = 256 / BITSIZEOF(u8);
|
||||
public:
|
||||
constexpr IHash256Generator() = default;
|
||||
virtual constexpr ~IHash256Generator() { /* ... */ }
|
||||
public:
|
||||
void Initialize() {
|
||||
return this->DoInitialize();
|
||||
}
|
||||
|
||||
void Update(const void *data, size_t size) {
|
||||
/* Check pre-conditions. */
|
||||
AMS_ASSERT(data != nullptr);
|
||||
|
||||
return this->DoUpdate(data, size);
|
||||
}
|
||||
|
||||
void GetHash(void *dst, size_t dst_size) {
|
||||
/* Check pre-conditions. */
|
||||
AMS_ASSERT(dst_size == HashSize);
|
||||
|
||||
return this->GetHash(dst, dst_size);
|
||||
}
|
||||
protected:
|
||||
virtual void DoInitialize() = 0;
|
||||
virtual void DoUpdate(const void *data, size_t size) = 0;
|
||||
virtual void DoGetHash(void *dst, size_t dst_size) = 0;
|
||||
};
|
||||
|
||||
class IHash256GeneratorFactory {
|
||||
public:
|
||||
constexpr IHash256GeneratorFactory() = default;
|
||||
virtual constexpr ~IHash256GeneratorFactory() { /* ... */ }
|
||||
|
||||
std::unique_ptr<IHash256Generator> Create() {
|
||||
return this->DoCreate();
|
||||
}
|
||||
|
||||
void GenerateHash(void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
/* Check pre-conditions. */
|
||||
AMS_ASSERT(dst != nullptr);
|
||||
AMS_ASSERT(src != nullptr);
|
||||
AMS_ASSERT(dst_size == IHash256Generator::HashSize);
|
||||
|
||||
return this->DoGenerateHash(dst, dst_size, src, src_size);
|
||||
}
|
||||
protected:
|
||||
virtual std::unique_ptr<IHash256Generator> DoCreate() = 0;
|
||||
virtual void DoGenerateHash(void *dst, size_t dst_size, const void *src, size_t src_size) = 0;
|
||||
};
|
||||
|
||||
class IHash256GeneratorFactorySelector {
|
||||
public:
|
||||
constexpr IHash256GeneratorFactorySelector() = default;
|
||||
virtual constexpr ~IHash256GeneratorFactorySelector() { /* ... */ }
|
||||
|
||||
IHash256GeneratorFactory *GetFactory() { return this->DoGetFactory(); }
|
||||
protected:
|
||||
virtual IHash256GeneratorFactory *DoGetFactory() = 0;
|
||||
};
|
||||
|
||||
}
|
|
@ -37,7 +37,7 @@ namespace ams::fssystem {
|
|||
IntegrityRomFsStorage() : m_mutex() { /* ... */ }
|
||||
virtual ~IntegrityRomFsStorage() override { this->Finalize(); }
|
||||
|
||||
Result Initialize(save::HierarchicalIntegrityVerificationInformation level_hash_info, Hash master_hash, save::HierarchicalIntegrityVerificationStorage::HierarchicalStorageInformation storage_info, IBufferManager *bm);
|
||||
Result Initialize(save::HierarchicalIntegrityVerificationInformation level_hash_info, Hash master_hash, save::HierarchicalIntegrityVerificationStorage::HierarchicalStorageInformation storage_info, IBufferManager *bm, IHash256GeneratorFactory *hgf);
|
||||
void Finalize();
|
||||
|
||||
virtual Result Read(s64 offset, void *buffer, size_t size) override {
|
||||
|
|
|
@ -17,11 +17,15 @@
|
|||
#include <vapours.hpp>
|
||||
#include <stratosphere/fs/impl/fs_newable.hpp>
|
||||
#include <stratosphere/fs/fs_istorage.hpp>
|
||||
#include <stratosphere/fssystem/fssystem_compression_common.hpp>
|
||||
#include <stratosphere/fssystem/fssystem_i_hash_256_generator.hpp>
|
||||
#include <stratosphere/fssystem/fssystem_asynchronous_access.hpp>
|
||||
#include <stratosphere/fssystem/fssystem_nca_header.hpp>
|
||||
#include <stratosphere/fssystem/buffers/fssystem_i_buffer_manager.hpp>
|
||||
|
||||
namespace ams::fssystem {
|
||||
|
||||
class CompressedStorage;
|
||||
class AesCtrCounterExtendedStorage;
|
||||
class IndirectStorage;
|
||||
class SparseStorage;
|
||||
|
@ -57,6 +61,11 @@ namespace ams::fssystem {
|
|||
};
|
||||
static_assert(util::is_pod<NcaCryptoConfiguration>::value);
|
||||
|
||||
struct NcaCompressionConfiguration {
|
||||
GetDecompressorFunction get_decompressor;
|
||||
};
|
||||
static_assert(util::is_pod<NcaCompressionConfiguration>::value);
|
||||
|
||||
constexpr inline bool IsInvalidKeyTypeValue(s32 key_type) {
|
||||
return key_type < 0;
|
||||
}
|
||||
|
@ -87,22 +96,22 @@ namespace ams::fssystem {
|
|||
private:
|
||||
NcaHeader m_header;
|
||||
u8 m_decryption_keys[NcaHeader::DecryptionKey_Count][NcaCryptoConfiguration::Aes128KeySize];
|
||||
std::shared_ptr<fs::IStorage> m_shared_base_storage;
|
||||
std::shared_ptr<fs::IStorage> m_body_storage;
|
||||
std::unique_ptr<fs::IStorage> m_header_storage;
|
||||
fs::IStorage *m_body_storage;
|
||||
u8 m_external_decryption_key[NcaCryptoConfiguration::Aes128KeySize];
|
||||
DecryptAesCtrFunction m_decrypt_aes_ctr;
|
||||
DecryptAesCtrFunction m_decrypt_aes_ctr_external;
|
||||
bool m_is_software_aes_prioritized;
|
||||
NcaHeader::EncryptionType m_header_encryption_type;
|
||||
GetDecompressorFunction m_get_decompressor;
|
||||
IHash256GeneratorFactory *m_hash_generator_factory;
|
||||
public:
|
||||
NcaReader();
|
||||
~NcaReader();
|
||||
|
||||
Result Initialize(fs::IStorage *base_storage, const NcaCryptoConfiguration &crypto_cfg);
|
||||
Result Initialize(std::shared_ptr<fs::IStorage> base_storage, const NcaCryptoConfiguration &crypto_cfg);
|
||||
Result Initialize(std::shared_ptr<fs::IStorage> base_storage, const NcaCryptoConfiguration &crypto_cfg, const NcaCompressionConfiguration &compression_cfg, IHash256GeneratorFactorySelector *hgf_selector);
|
||||
|
||||
fs::IStorage *GetBodyStorage();
|
||||
std::shared_ptr<fs::IStorage> GetSharedBodyStorage();
|
||||
u32 GetMagic() const;
|
||||
NcaHeader::DistributionType GetDistributionType() const;
|
||||
NcaHeader::ContentType GetContentType() const;
|
||||
|
@ -124,7 +133,7 @@ namespace ams::fssystem {
|
|||
void GetEncryptedKey(void *dst, size_t size) const;
|
||||
const void *GetDecryptionKey(s32 index) const;
|
||||
bool HasValidInternalKey() const;
|
||||
bool HasInternalDecryptionKeyForAesHardwareSpeedEmulation() const;
|
||||
bool HasInternalDecryptionKeyForAesHw() const;
|
||||
bool IsSoftwareAesPrioritized() const;
|
||||
void PrioritizeSoftwareAes();
|
||||
bool HasExternalDecryptionKey() const;
|
||||
|
@ -136,7 +145,11 @@ namespace ams::fssystem {
|
|||
NcaHeader::EncryptionType GetEncryptionType() const;
|
||||
Result ReadHeader(NcaFsHeader *dst, s32 index) const;
|
||||
|
||||
Result VerifyHeaderSign2(const void *key, size_t key_size);
|
||||
GetDecompressorFunction GetDecompressor() const;
|
||||
IHash256GeneratorFactory *GetHashGeneratorFactory() const;
|
||||
|
||||
void GetHeaderSign2(void *dst, size_t size);
|
||||
void GetHeaderSign2TargetHash(void *dst, size_t size);
|
||||
};
|
||||
|
||||
class NcaFsHeaderReader : public ::ams::fs::impl::Newable {
|
||||
|
@ -153,8 +166,9 @@ namespace ams::fssystem {
|
|||
Result Initialize(const NcaReader &reader, s32 index);
|
||||
bool IsInitialized() const { return m_fs_index >= 0; }
|
||||
|
||||
NcaFsHeader &GetData() { return m_data; }
|
||||
const NcaFsHeader &GetData() const { return m_data; }
|
||||
// NcaFsHeader &GetData() { return m_data; }
|
||||
// const NcaFsHeader &GetData() const { return m_data; }
|
||||
|
||||
void GetRawData(void *dst, size_t dst_size) const;
|
||||
|
||||
NcaFsHeader::HashData &GetHashData();
|
||||
|
@ -170,57 +184,85 @@ namespace ams::fssystem {
|
|||
bool ExistsSparseLayer() const;
|
||||
NcaSparseInfo &GetSparseInfo();
|
||||
const NcaSparseInfo &GetSparseInfo() const;
|
||||
bool ExistsCompressionLayer() const;
|
||||
NcaCompressionInfo &GetCompressionInfo();
|
||||
const NcaCompressionInfo &GetCompressionInfo() const;
|
||||
};
|
||||
|
||||
class NcaFileSystemDriver : public ::ams::fs::impl::Newable {
|
||||
NON_COPYABLE(NcaFileSystemDriver);
|
||||
NON_MOVEABLE(NcaFileSystemDriver);
|
||||
public:
|
||||
class StorageOption;
|
||||
class StorageOptionWithHeaderReader;
|
||||
private:
|
||||
struct StorageContext {
|
||||
bool open_raw_storage;
|
||||
std::shared_ptr<fs::IStorage> body_substorage;
|
||||
std::shared_ptr<fssystem::SparseStorage> current_sparse_storage;
|
||||
std::shared_ptr<fs::IStorage> sparse_storage_meta_storage;
|
||||
std::shared_ptr<fssystem::SparseStorage> original_sparse_storage;
|
||||
void *external_current_sparse_storage; /* TODO: Add real type? */
|
||||
void *external_original_sparse_storage; /* TODO: Add real type? */
|
||||
std::shared_ptr<fs::IStorage> aes_ctr_ex_storage_meta_storage;
|
||||
std::shared_ptr<fs::IStorage> aes_ctr_ex_storage_data_storage;
|
||||
std::shared_ptr<fssystem::AesCtrCounterExtendedStorage> aes_ctr_ex_storage;
|
||||
std::shared_ptr<fs::IStorage> indirect_storage_meta_storage;
|
||||
std::shared_ptr<fssystem::IndirectStorage> indirect_storage;
|
||||
std::shared_ptr<fs::IStorage> fs_data_storage;
|
||||
std::shared_ptr<fs::IStorage> compressed_storage_meta_storage;
|
||||
std::shared_ptr<fssystem::CompressedStorage> compressed_storage;
|
||||
};
|
||||
|
||||
enum AlignmentStorageRequirement {
|
||||
/* TODO */
|
||||
AlignmentStorageRequirement_CacheBlockSize = 0,
|
||||
AlignmentStorageRequirement_None = 1,
|
||||
};
|
||||
private:
|
||||
std::shared_ptr<NcaReader> m_original_reader;
|
||||
std::shared_ptr<NcaReader> m_reader;
|
||||
MemoryResource * const m_allocator;
|
||||
fssystem::IBufferManager * const m_buffer_manager;
|
||||
fssystem::IHash256GeneratorFactorySelector * const m_hash_generator_factory_selector;
|
||||
public:
|
||||
static Result SetupFsHeaderReader(NcaFsHeaderReader *out, const NcaReader &reader, s32 fs_index);
|
||||
public:
|
||||
NcaFileSystemDriver(std::shared_ptr<NcaReader> reader, MemoryResource *allocator, IBufferManager *buffer_manager) : m_original_reader(), m_reader(reader), m_allocator(allocator), m_buffer_manager(buffer_manager) {
|
||||
NcaFileSystemDriver(std::shared_ptr<NcaReader> reader, MemoryResource *allocator, IBufferManager *buffer_manager, IHash256GeneratorFactorySelector *hgf_selector) : m_original_reader(), m_reader(reader), m_allocator(allocator), m_buffer_manager(buffer_manager), m_hash_generator_factory_selector(hgf_selector) {
|
||||
AMS_ASSERT(m_reader != nullptr);
|
||||
AMS_ASSERT(m_hash_generator_factory_selector != nullptr);
|
||||
}
|
||||
|
||||
NcaFileSystemDriver(std::shared_ptr<NcaReader> original_reader, std::shared_ptr<NcaReader> reader, MemoryResource *allocator, IBufferManager *buffer_manager) : m_original_reader(original_reader), m_reader(reader), m_allocator(allocator), m_buffer_manager(buffer_manager) {
|
||||
NcaFileSystemDriver(std::shared_ptr<NcaReader> original_reader, std::shared_ptr<NcaReader> reader, MemoryResource *allocator, IBufferManager *buffer_manager, IHash256GeneratorFactorySelector *hgf_selector) : m_original_reader(original_reader), m_reader(reader), m_allocator(allocator), m_buffer_manager(buffer_manager), m_hash_generator_factory_selector(hgf_selector) {
|
||||
AMS_ASSERT(m_reader != nullptr);
|
||||
AMS_ASSERT(m_hash_generator_factory_selector != nullptr);
|
||||
}
|
||||
|
||||
Result OpenRawStorage(std::shared_ptr<fs::IStorage> *out, s32 fs_index);
|
||||
|
||||
Result OpenStorage(std::shared_ptr<fs::IStorage> *out, NcaFsHeaderReader *out_header_reader, s32 fs_index);
|
||||
Result OpenStorage(std::shared_ptr<fs::IStorage> *out, StorageOption *option);
|
||||
|
||||
Result OpenStorage(std::shared_ptr<fs::IStorage> *out, s32 fs_index) {
|
||||
NcaFsHeaderReader dummy;
|
||||
return this->OpenStorage(out, std::addressof(dummy), fs_index);
|
||||
}
|
||||
|
||||
Result OpenDecryptableStorage(std::shared_ptr<fs::IStorage> *out, StorageOption *option, bool indirect_needed);
|
||||
|
||||
Result OpenStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<IAsynchronousAccessSplitter> *out_splitter, NcaFsHeaderReader *out_header_reader, s32 fs_index);
|
||||
private:
|
||||
class BaseStorage;
|
||||
Result OpenStorageImpl(std::shared_ptr<fs::IStorage> *out, NcaFsHeaderReader *out_header_reader, s32 fs_index, StorageContext *ctx);
|
||||
|
||||
Result CreateBaseStorage(BaseStorage *out, StorageOption *option);
|
||||
Result OpenIndirectableStorageAsOriginal(std::shared_ptr<fs::IStorage> *out, const NcaFsHeaderReader *header_reader, StorageContext *ctx);
|
||||
|
||||
Result CreateDecryptableStorage(std::unique_ptr<fs::IStorage> *out, StorageOption *option, BaseStorage *base_storage);
|
||||
Result CreateAesXtsStorage(std::unique_ptr<fs::IStorage> *out, BaseStorage *base_storage);
|
||||
Result CreateAesCtrStorage(std::unique_ptr<fs::IStorage> *out, BaseStorage *base_storage);
|
||||
Result CreateAesCtrExStorage(std::unique_ptr<fs::IStorage> *out, StorageOption *option, BaseStorage *base_storage);
|
||||
Result CreateBodySubStorage(std::shared_ptr<fs::IStorage> *out, s64 offset, s64 size);
|
||||
|
||||
Result CreateIndirectStorage(std::unique_ptr<fs::IStorage> *out, StorageOption *option, std::unique_ptr<fs::IStorage> base_storage);
|
||||
Result CreateAesCtrStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fs::IStorage> base_storage, s64 offset, const NcaAesCtrUpperIv &upper_iv, AlignmentStorageRequirement alignment_storage_requirement);
|
||||
Result CreateAesXtsStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fs::IStorage> base_storage, s64 offset);
|
||||
|
||||
Result CreateVerificationStorage(std::unique_ptr<fs::IStorage> *out, std::unique_ptr<fs::IStorage> base_storage, NcaFsHeaderReader *header_reader);
|
||||
Result CreateSha256Storage(std::unique_ptr<fs::IStorage> *out, std::unique_ptr<fs::IStorage> base_storage, NcaFsHeaderReader *header_reader);
|
||||
Result CreateIntegrityVerificationStorage(std::unique_ptr<fs::IStorage> *out, std::unique_ptr<fs::IStorage> base_storage, NcaFsHeaderReader *header_reader);
|
||||
Result CreateSparseStorageMetaStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fs::IStorage> base_storage, s64 offset, const NcaAesCtrUpperIv &upper_iv, const NcaSparseInfo &sparse_info);
|
||||
Result CreateSparseStorageCore(std::shared_ptr<fssystem::SparseStorage> *out, std::shared_ptr<fs::IStorage> base_storage, s64 base_size, std::shared_ptr<fs::IStorage> meta_storage, const NcaSparseInfo &sparse_info, bool external_info);
|
||||
Result CreateSparseStorage(std::shared_ptr<fs::IStorage> *out, s64 *out_fs_data_offset, std::shared_ptr<fssystem::SparseStorage> *out_sparse_storage, std::shared_ptr<fs::IStorage> *out_meta_storage, s32 index, const NcaAesCtrUpperIv &upper_iv, const NcaSparseInfo &sparse_info);
|
||||
|
||||
Result CreateAesCtrExMetaStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fs::IStorage> base_storage, s64 offset, const NcaAesCtrUpperIv &upper_iv, const NcaPatchInfo &patch_info);
|
||||
Result CreateAesCtrExStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::AesCtrCounterExtendedStorage> *out_ext, std::shared_ptr<fs::IStorage> base_storage, std::shared_ptr<fs::IStorage> meta_storage, s64 counter_offset, const NcaAesCtrUpperIv &upper_iv, const NcaPatchInfo &patch_info);
|
||||
|
||||
Result CreateIndirectStorageMetaStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fs::IStorage> base_storage, const NcaPatchInfo &patch_info);
|
||||
Result CreateIndirectStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::IndirectStorage> *out_ind, std::shared_ptr<fs::IStorage> base_storage, std::shared_ptr<fs::IStorage> original_data_storage, std::shared_ptr<fs::IStorage> meta_storage, const NcaPatchInfo &patch_info);
|
||||
|
||||
Result CreateSha256Storage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fs::IStorage> base_storage, const NcaFsHeader::HashData::HierarchicalSha256Data &sha256_data);
|
||||
|
||||
Result CreateIntegrityVerificationStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fs::IStorage> base_storage, const NcaFsHeader::HashData::IntegrityMetaInfo &meta_info);
|
||||
|
||||
Result CreateCompressedStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::CompressedStorage> *out_cmp, std::shared_ptr<fs::IStorage> *out_meta, std::shared_ptr<fs::IStorage> base_storage, const NcaCompressionInfo &compression_info);
|
||||
public:
|
||||
Result CreateCompressedStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::CompressedStorage> *out_cmp, std::shared_ptr<fs::IStorage> *out_meta, std::shared_ptr<fs::IStorage> base_storage, const NcaCompressionInfo &compression_info, GetDecompressorFunction get_decompressor, MemoryResource *allocator, IBufferManager *buffer_manager);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -20,131 +20,131 @@
|
|||
|
||||
namespace ams::fssystem {
|
||||
|
||||
class NcaFileSystemDriver::StorageOption {
|
||||
private:
|
||||
friend class NcaFileSystemDriver;
|
||||
private:
|
||||
const s32 m_fs_index;
|
||||
NcaFsHeaderReader * const m_header_reader;
|
||||
fs::IStorage *m_data_storage;
|
||||
s64 m_data_storage_size;
|
||||
fs::IStorage *m_aes_ctr_ex_table_storage;
|
||||
AesCtrCounterExtendedStorage *m_aes_ctr_ex_storage_raw;
|
||||
fs::IStorage *m_aes_ctr_ex_storage;
|
||||
IndirectStorage *m_indirect_storage;
|
||||
SparseStorage *m_sparse_storage;
|
||||
public:
|
||||
explicit StorageOption(NcaFsHeaderReader *reader) : m_fs_index(reader->GetFsIndex()), m_header_reader(reader), m_data_storage(), m_data_storage_size(), m_aes_ctr_ex_table_storage(), m_aes_ctr_ex_storage_raw(), m_aes_ctr_ex_storage(), m_indirect_storage(), m_sparse_storage() {
|
||||
AMS_ASSERT(m_header_reader != nullptr);
|
||||
}
|
||||
|
||||
StorageOption(NcaFsHeaderReader *reader, s32 index) : m_fs_index(index), m_header_reader(reader), m_data_storage(), m_data_storage_size(), m_aes_ctr_ex_table_storage(), m_aes_ctr_ex_storage_raw(), m_aes_ctr_ex_storage(), m_indirect_storage(), m_sparse_storage() {
|
||||
AMS_ASSERT(m_header_reader != nullptr);
|
||||
AMS_ASSERT(0 <= index && index < NcaHeader::FsCountMax);
|
||||
}
|
||||
|
||||
s32 GetFsIndex() const { return m_fs_index; }
|
||||
NcaFsHeaderReader &GetHeaderReader() { return *m_header_reader; }
|
||||
const NcaFsHeaderReader &GetHeaderReader() const { return *m_header_reader; }
|
||||
fs::SubStorage GetDataStorage() const { return fs::SubStorage(m_data_storage, 0, m_data_storage_size); }
|
||||
fs::IStorage *GetAesCtrExTableStorage() const { return m_aes_ctr_ex_table_storage; }
|
||||
fs::IStorage *GetAesCtrExStorage() const { return m_aes_ctr_ex_storage; }
|
||||
AesCtrCounterExtendedStorage *GetAesCtrExStorageRaw() const { return m_aes_ctr_ex_storage_raw; }
|
||||
IndirectStorage *GetIndirectStorage() const { return m_indirect_storage; }
|
||||
SparseStorage *GetSparseStorage() const { return m_sparse_storage; }
|
||||
private:
|
||||
void SetDataStorage(fs::IStorage *storage, s64 size) {
|
||||
AMS_ASSERT(storage != nullptr);
|
||||
AMS_ASSERT(size >= 0);
|
||||
m_data_storage = storage;
|
||||
m_data_storage_size = size;
|
||||
}
|
||||
|
||||
void SetAesCtrExTableStorage(fs::IStorage *storage) { AMS_ASSERT(storage != nullptr); m_aes_ctr_ex_table_storage = storage; }
|
||||
void SetAesCtrExStorage(fs::IStorage *storage) { AMS_ASSERT(storage != nullptr); m_aes_ctr_ex_storage = storage; }
|
||||
void SetAesCtrExStorageRaw(AesCtrCounterExtendedStorage *storage) { AMS_ASSERT(storage != nullptr); m_aes_ctr_ex_storage_raw = storage; }
|
||||
void SetIndirectStorage(IndirectStorage *storage) { AMS_ASSERT(storage != nullptr); m_indirect_storage = storage; }
|
||||
void SetSparseStorage(SparseStorage *storage) { AMS_ASSERT(storage != nullptr); m_sparse_storage = storage; }
|
||||
};
|
||||
|
||||
class NcaFileSystemDriver::StorageOptionWithHeaderReader : public NcaFileSystemDriver::StorageOption {
|
||||
private:
|
||||
NcaFsHeaderReader m_header_reader_data;
|
||||
public:
|
||||
explicit StorageOptionWithHeaderReader(s32 index) : StorageOption(std::addressof(m_header_reader_data), index) { /* ... */ }
|
||||
};
|
||||
|
||||
class NcaFileSystemDriver::BaseStorage {
|
||||
private:
|
||||
std::unique_ptr<fs::IStorage> m_storage;
|
||||
fs::SubStorage m_sub_storage;
|
||||
s64 m_storage_offset;
|
||||
NcaAesCtrUpperIv m_aes_ctr_upper_iv;
|
||||
public:
|
||||
BaseStorage() : m_storage(), m_sub_storage(), m_storage_offset(0) {
|
||||
m_aes_ctr_upper_iv.value = 0;
|
||||
}
|
||||
|
||||
explicit BaseStorage(const fs::SubStorage &ss) : m_storage(), m_sub_storage(ss), m_storage_offset(0) {
|
||||
m_aes_ctr_upper_iv.value = 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
BaseStorage(T s, s64 offset, s64 size) : m_storage(), m_sub_storage(s, offset, size), m_storage_offset(0) {
|
||||
m_aes_ctr_upper_iv.value = 0;
|
||||
}
|
||||
|
||||
void SetStorage(std::unique_ptr<fs::IStorage> &&storage) {
|
||||
m_storage = std::move(storage);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void SetStorage(T storage, s64 offset, s64 size) {
|
||||
m_sub_storage = fs::SubStorage(storage, offset, size);
|
||||
}
|
||||
|
||||
std::unique_ptr<fs::IStorage> MakeStorage() {
|
||||
if (m_storage != nullptr) {
|
||||
return std::move(m_storage);
|
||||
}
|
||||
return std::make_unique<fs::SubStorage>(m_sub_storage);
|
||||
}
|
||||
|
||||
std::unique_ptr<fs::IStorage> GetStorage() {
|
||||
return std::move(m_storage);
|
||||
}
|
||||
|
||||
Result GetSubStorage(fs::SubStorage *out, s64 offset, s64 size) {
|
||||
s64 storage_size = 0;
|
||||
|
||||
if (m_storage != nullptr) {
|
||||
R_TRY(m_storage->GetSize(std::addressof(storage_size)));
|
||||
R_UNLESS(offset + size <= storage_size, fs::ResultNcaBaseStorageOutOfRangeA());
|
||||
*out = fs::SubStorage(m_storage.get(), offset, size);
|
||||
} else {
|
||||
R_TRY(m_sub_storage.GetSize(std::addressof(storage_size)));
|
||||
R_UNLESS(offset + size <= storage_size, fs::ResultNcaBaseStorageOutOfRangeA());
|
||||
*out = fs::SubStorage(std::addressof(m_sub_storage), offset, size);
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void SetStorageOffset(s64 offset) {
|
||||
m_storage_offset = offset;
|
||||
}
|
||||
|
||||
s64 GetStorageOffset() const {
|
||||
return m_storage_offset;
|
||||
}
|
||||
|
||||
void SetAesCtrUpperIv(NcaAesCtrUpperIv v) {
|
||||
m_aes_ctr_upper_iv = v;
|
||||
}
|
||||
|
||||
const NcaAesCtrUpperIv GetAesCtrUpperIv() const {
|
||||
return m_aes_ctr_upper_iv;
|
||||
}
|
||||
};
|
||||
// class NcaFileSystemDriver::StorageOption {
|
||||
// private:
|
||||
// friend class NcaFileSystemDriver;
|
||||
// private:
|
||||
// const s32 m_fs_index;
|
||||
// NcaFsHeaderReader * const m_header_reader;
|
||||
// fs::IStorage *m_data_storage;
|
||||
// s64 m_data_storage_size;
|
||||
// fs::IStorage *m_aes_ctr_ex_table_storage;
|
||||
// AesCtrCounterExtendedStorage *m_aes_ctr_ex_storage_raw;
|
||||
// fs::IStorage *m_aes_ctr_ex_storage;
|
||||
// IndirectStorage *m_indirect_storage;
|
||||
// SparseStorage *m_sparse_storage;
|
||||
// public:
|
||||
// explicit StorageOption(NcaFsHeaderReader *reader) : m_fs_index(reader->GetFsIndex()), m_header_reader(reader), m_data_storage(), m_data_storage_size(), m_aes_ctr_ex_table_storage(), m_aes_ctr_ex_storage_raw(), m_aes_ctr_ex_storage(), m_indirect_storage(), m_sparse_storage() {
|
||||
// AMS_ASSERT(m_header_reader != nullptr);
|
||||
// }
|
||||
//
|
||||
// StorageOption(NcaFsHeaderReader *reader, s32 index) : m_fs_index(index), m_header_reader(reader), m_data_storage(), m_data_storage_size(), m_aes_ctr_ex_table_storage(), m_aes_ctr_ex_storage_raw(), m_aes_ctr_ex_storage(), m_indirect_storage(), m_sparse_storage() {
|
||||
// AMS_ASSERT(m_header_reader != nullptr);
|
||||
// AMS_ASSERT(0 <= index && index < NcaHeader::FsCountMax);
|
||||
// }
|
||||
//
|
||||
// s32 GetFsIndex() const { return m_fs_index; }
|
||||
// NcaFsHeaderReader &GetHeaderReader() { return *m_header_reader; }
|
||||
// const NcaFsHeaderReader &GetHeaderReader() const { return *m_header_reader; }
|
||||
// fs::SubStorage GetDataStorage() const { return fs::SubStorage(m_data_storage, 0, m_data_storage_size); }
|
||||
// fs::IStorage *GetAesCtrExTableStorage() const { return m_aes_ctr_ex_table_storage; }
|
||||
// fs::IStorage *GetAesCtrExStorage() const { return m_aes_ctr_ex_storage; }
|
||||
// AesCtrCounterExtendedStorage *GetAesCtrExStorageRaw() const { return m_aes_ctr_ex_storage_raw; }
|
||||
// IndirectStorage *GetIndirectStorage() const { return m_indirect_storage; }
|
||||
// SparseStorage *GetSparseStorage() const { return m_sparse_storage; }
|
||||
// private:
|
||||
// void SetDataStorage(fs::IStorage *storage, s64 size) {
|
||||
// AMS_ASSERT(storage != nullptr);
|
||||
// AMS_ASSERT(size >= 0);
|
||||
// m_data_storage = storage;
|
||||
// m_data_storage_size = size;
|
||||
// }
|
||||
//
|
||||
// void SetAesCtrExTableStorage(fs::IStorage *storage) { AMS_ASSERT(storage != nullptr); m_aes_ctr_ex_table_storage = storage; }
|
||||
// void SetAesCtrExStorage(fs::IStorage *storage) { AMS_ASSERT(storage != nullptr); m_aes_ctr_ex_storage = storage; }
|
||||
// void SetAesCtrExStorageRaw(AesCtrCounterExtendedStorage *storage) { AMS_ASSERT(storage != nullptr); m_aes_ctr_ex_storage_raw = storage; }
|
||||
// void SetIndirectStorage(IndirectStorage *storage) { AMS_ASSERT(storage != nullptr); m_indirect_storage = storage; }
|
||||
// void SetSparseStorage(SparseStorage *storage) { AMS_ASSERT(storage != nullptr); m_sparse_storage = storage; }
|
||||
// };
|
||||
//
|
||||
// class NcaFileSystemDriver::StorageOptionWithHeaderReader : public NcaFileSystemDriver::StorageOption {
|
||||
// private:
|
||||
// NcaFsHeaderReader m_header_reader_data;
|
||||
// public:
|
||||
// explicit StorageOptionWithHeaderReader(s32 index) : StorageOption(std::addressof(m_header_reader_data), index) { /* ... */ }
|
||||
// };
|
||||
//
|
||||
// class NcaFileSystemDriver::BaseStorage {
|
||||
// private:
|
||||
// std::unique_ptr<fs::IStorage> m_storage;
|
||||
// fs::SubStorage m_sub_storage;
|
||||
// s64 m_storage_offset;
|
||||
// NcaAesCtrUpperIv m_aes_ctr_upper_iv;
|
||||
// public:
|
||||
// BaseStorage() : m_storage(), m_sub_storage(), m_storage_offset(0) {
|
||||
// m_aes_ctr_upper_iv.value = 0;
|
||||
// }
|
||||
//
|
||||
// explicit BaseStorage(const fs::SubStorage &ss) : m_storage(), m_sub_storage(ss), m_storage_offset(0) {
|
||||
// m_aes_ctr_upper_iv.value = 0;
|
||||
// }
|
||||
//
|
||||
// template<typename T>
|
||||
// BaseStorage(T s, s64 offset, s64 size) : m_storage(), m_sub_storage(s, offset, size), m_storage_offset(0) {
|
||||
// m_aes_ctr_upper_iv.value = 0;
|
||||
// }
|
||||
//
|
||||
// void SetStorage(std::unique_ptr<fs::IStorage> &&storage) {
|
||||
// m_storage = std::move(storage);
|
||||
// }
|
||||
//
|
||||
// template<typename T>
|
||||
// void SetStorage(T storage, s64 offset, s64 size) {
|
||||
// m_sub_storage = fs::SubStorage(storage, offset, size);
|
||||
// }
|
||||
//
|
||||
// std::unique_ptr<fs::IStorage> MakeStorage() {
|
||||
// if (m_storage != nullptr) {
|
||||
// return std::move(m_storage);
|
||||
// }
|
||||
// return std::make_unique<fs::SubStorage>(m_sub_storage);
|
||||
// }
|
||||
//
|
||||
// std::unique_ptr<fs::IStorage> GetStorage() {
|
||||
// return std::move(m_storage);
|
||||
// }
|
||||
//
|
||||
// Result GetSubStorage(fs::SubStorage *out, s64 offset, s64 size) {
|
||||
// s64 storage_size = 0;
|
||||
//
|
||||
// if (m_storage != nullptr) {
|
||||
// R_TRY(m_storage->GetSize(std::addressof(storage_size)));
|
||||
// R_UNLESS(offset + size <= storage_size, fs::ResultNcaBaseStorageOutOfRangeA());
|
||||
// *out = fs::SubStorage(m_storage.get(), offset, size);
|
||||
// } else {
|
||||
// R_TRY(m_sub_storage.GetSize(std::addressof(storage_size)));
|
||||
// R_UNLESS(offset + size <= storage_size, fs::ResultNcaBaseStorageOutOfRangeA());
|
||||
// *out = fs::SubStorage(std::addressof(m_sub_storage), offset, size);
|
||||
// }
|
||||
//
|
||||
// return ResultSuccess();
|
||||
// }
|
||||
//
|
||||
// void SetStorageOffset(s64 offset) {
|
||||
// m_storage_offset = offset;
|
||||
// }
|
||||
//
|
||||
// s64 GetStorageOffset() const {
|
||||
// return m_storage_offset;
|
||||
// }
|
||||
//
|
||||
// void SetAesCtrUpperIv(NcaAesCtrUpperIv v) {
|
||||
// m_aes_ctr_upper_iv = v;
|
||||
// }
|
||||
//
|
||||
// const NcaAesCtrUpperIv GetAesCtrUpperIv() const {
|
||||
// return m_aes_ctr_upper_iv;
|
||||
// }
|
||||
// };
|
||||
|
||||
}
|
||||
|
|
|
@ -181,6 +181,11 @@ namespace ams::fssystem {
|
|||
};
|
||||
static_assert(util::is_pod<NcaSparseInfo>::value);
|
||||
|
||||
struct NcaCompressionInfo {
|
||||
NcaBucketInfo bucket;
|
||||
};
|
||||
static_assert(util::is_pod<NcaCompressionInfo>::value);
|
||||
|
||||
struct NcaFsHeader {
|
||||
static constexpr size_t Size = 0x200;
|
||||
static constexpr size_t HashDataOffset = 0x8;
|
||||
|
@ -263,7 +268,8 @@ namespace ams::fssystem {
|
|||
NcaPatchInfo patch_info;
|
||||
NcaAesCtrUpperIv aes_ctr_upper_iv;
|
||||
NcaSparseInfo sparse_info;
|
||||
u8 pad[0x88];
|
||||
NcaCompressionInfo compression_info;
|
||||
u8 pad[0x68];
|
||||
};
|
||||
static_assert(sizeof(NcaFsHeader) == NcaFsHeader::Size);
|
||||
static_assert(util::is_pod<NcaFsHeader>::value);
|
||||
|
|
|
@ -157,7 +157,7 @@ namespace ams::fssystem::save {
|
|||
HierarchicalIntegrityVerificationStorage() : m_buffers(nullptr), m_mutex(nullptr), m_data_size(-1), m_is_written_for_rollback(false) { /* ... */ }
|
||||
virtual ~HierarchicalIntegrityVerificationStorage() override { this->Finalize(); }
|
||||
|
||||
Result Initialize(const HierarchicalIntegrityVerificationInformation &info, HierarchicalStorageInformation storage, FileSystemBufferManagerSet *bufs, os::SdkRecursiveMutex *mtx, fs::StorageType storage_type);
|
||||
Result Initialize(const HierarchicalIntegrityVerificationInformation &info, HierarchicalStorageInformation storage, FileSystemBufferManagerSet *bufs, IHash256GeneratorFactory *hgf, os::SdkRecursiveMutex *mtx, fs::StorageType storage_type);
|
||||
void Finalize();
|
||||
|
||||
virtual Result Read(s64 offset, void *buffer, size_t size) override;
|
||||
|
|
|
@ -47,11 +47,12 @@ namespace ams::fssystem::save {
|
|||
fs::HashSalt m_salt;
|
||||
bool m_is_real_data;
|
||||
fs::StorageType m_storage_type;
|
||||
fssystem::IHash256GeneratorFactory *m_hash_generator_factory;
|
||||
public:
|
||||
IntegrityVerificationStorage() : m_verification_block_size(0), m_verification_block_order(0), m_upper_layer_verification_block_size(0), m_upper_layer_verification_block_order(0), m_buffer_manager(nullptr) { /* ... */ }
|
||||
virtual ~IntegrityVerificationStorage() override { this->Finalize(); }
|
||||
|
||||
Result Initialize(fs::SubStorage hs, fs::SubStorage ds, s64 verif_block_size, s64 upper_layer_verif_block_size, IBufferManager *bm, const fs::HashSalt &salt, bool is_real_data, fs::StorageType storage_type);
|
||||
Result Initialize(fs::SubStorage hs, fs::SubStorage ds, s64 verif_block_size, s64 upper_layer_verif_block_size, IBufferManager *bm, fssystem::IHash256GeneratorFactory *hgf, const fs::HashSalt &salt, bool is_real_data, fs::StorageType storage_type);
|
||||
void Finalize();
|
||||
|
||||
virtual Result Read(s64 offset, void *buffer, size_t size) override;
|
||||
|
@ -65,7 +66,10 @@ namespace ams::fssystem::save {
|
|||
virtual Result OperateRange(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override;
|
||||
using IStorage::OperateRange;
|
||||
|
||||
void CalcBlockHash(BlockHash *out, const void *buffer, size_t block_size) const;
|
||||
void CalcBlockHash(BlockHash *out, const void *buffer, size_t block_size) const {
|
||||
auto generator = m_hash_generator_factory->Create();
|
||||
return this->CalcBlockHash(out, buffer, block_size, generator);
|
||||
}
|
||||
|
||||
s64 GetBlockSize() const {
|
||||
return m_verification_block_size;
|
||||
|
@ -73,9 +77,11 @@ namespace ams::fssystem::save {
|
|||
private:
|
||||
Result ReadBlockSignature(void *dst, size_t dst_size, s64 offset, size_t size);
|
||||
Result WriteBlockSignature(const void *src, size_t src_size, s64 offset, size_t size);
|
||||
Result VerifyHash(const void *buf, BlockHash *hash);
|
||||
Result VerifyHash(const void *buf, BlockHash *hash, std::unique_ptr<fssystem::IHash256Generator> &generator);
|
||||
|
||||
void CalcBlockHash(BlockHash *out, const void *buffer) const {
|
||||
void CalcBlockHash(BlockHash *out, const void *buffer, size_t block_size, std::unique_ptr<fssystem::IHash256Generator> &generator) const;
|
||||
|
||||
void CalcBlockHash(BlockHash *out, const void *buffer, std::unique_ptr<fssystem::IHash256Generator> &generator) const {
|
||||
return this->CalcBlockHash(out, buffer, static_cast<size_t>(m_verification_block_size));
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue