mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-07-17 22:22:21 +02:00
fssystem: implement PartitionFileSystemMetaCore
This commit is contained in:
parent
0af2758fde
commit
34f3d0fab5
@ -17,6 +17,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "fssystem/fssystem_utility.hpp"
|
#include "fssystem/fssystem_utility.hpp"
|
||||||
#include "fssystem/fssystem_external_code.hpp"
|
#include "fssystem/fssystem_external_code.hpp"
|
||||||
|
#include "fssystem/fssystem_partition_file_system_meta.hpp"
|
||||||
#include "fssystem/fssystem_path_tool.hpp"
|
#include "fssystem/fssystem_path_tool.hpp"
|
||||||
#include "fssystem/fssystem_subdirectory_filesystem.hpp"
|
#include "fssystem/fssystem_subdirectory_filesystem.hpp"
|
||||||
#include "fssystem/fssystem_directory_redirection_filesystem.hpp"
|
#include "fssystem/fssystem_directory_redirection_filesystem.hpp"
|
||||||
|
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 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 <stratosphere/fs/fs_common.hpp>
|
||||||
|
#include <stratosphere/fs/impl/fs_newable.hpp>
|
||||||
|
|
||||||
|
namespace ams::fssystem {
|
||||||
|
|
||||||
|
namespace impl {
|
||||||
|
|
||||||
|
struct PartitionFileSystemFormat {
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct PartitionEntry {
|
||||||
|
u64 offset;
|
||||||
|
u64 size;
|
||||||
|
u32 name_offset;
|
||||||
|
u32 reserved;
|
||||||
|
};
|
||||||
|
static_assert(std::is_pod<PartitionEntry>::value);
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
static constexpr char VersionSignature[] = { 'P', 'F', 'S', '0' };
|
||||||
|
|
||||||
|
static constexpr size_t EntryNameLengthMax = ::ams::fs::EntryNameLengthMax;
|
||||||
|
static constexpr size_t FileDataAlignmentSize = 0x20;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Format>
|
||||||
|
class PartitionFileSystemMetaCore : public fs::impl::Newable {
|
||||||
|
public:
|
||||||
|
static constexpr size_t EntryNameLengthMax = Format::EntryNameLengthMax;
|
||||||
|
static constexpr size_t FileDataAlignmentSize = Format::FileDataAlignmentSize;
|
||||||
|
|
||||||
|
/* Forward declare header. */
|
||||||
|
struct PartitionFileSystemHeader;
|
||||||
|
|
||||||
|
using PartitionEntry = typename Format::PartitionEntry;
|
||||||
|
using ResultSignatureVerificationFailed = fs::ResultSha256PartitionSignatureVerificationFailed;
|
||||||
|
protected:
|
||||||
|
bool initialized;
|
||||||
|
PartitionFileSystemHeader *header;
|
||||||
|
PartitionEntry *entries;
|
||||||
|
char *name_table;
|
||||||
|
size_t meta_data_size;
|
||||||
|
MemoryResource *allocator;
|
||||||
|
char *buffer;
|
||||||
|
public:
|
||||||
|
PartitionFileSystemMetaCore() { /* ... */ }
|
||||||
|
~PartitionFileSystemMetaCore();
|
||||||
|
|
||||||
|
Result Initialize(fs::IStorage *storage, MemoryResource *allocator);
|
||||||
|
Result Initialize(fs::IStorage *storage, void *header, size_t header_size);
|
||||||
|
|
||||||
|
const PartitionEntry *GetEntry(s32 index) const;
|
||||||
|
s32 GetEntryCount() const;
|
||||||
|
s32 GetEntryIndex(const char *name) const;
|
||||||
|
const char *GetEntryName(s32 index) const;
|
||||||
|
size_t GetHeaderSize() const;
|
||||||
|
size_t GetMetaDataSize() const;
|
||||||
|
Result QueryMetaDataSize(size_t *out_size, fs::IStorage *storage) const;
|
||||||
|
protected:
|
||||||
|
void DeallocateBuffer();
|
||||||
|
};
|
||||||
|
|
||||||
|
using PartitionFileSystemMeta = PartitionFileSystemMetaCore<impl::PartitionFileSystemFormat>;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 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/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
|
namespace ams::fssystem {
|
||||||
|
|
||||||
|
template <typename Format>
|
||||||
|
struct PartitionFileSystemMetaCore<Format>::PartitionFileSystemHeader {
|
||||||
|
u32 signature;
|
||||||
|
s32 entry_count;
|
||||||
|
u32 name_table_size;
|
||||||
|
u32 reserved;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Format>
|
||||||
|
PartitionFileSystemMetaCore<Format>::~PartitionFileSystemMetaCore() {
|
||||||
|
this->DeallocateBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Format>
|
||||||
|
Result PartitionFileSystemMetaCore<Format>::Initialize(fs::IStorage *storage, MemoryResource *allocator) {
|
||||||
|
/* Determine the meta data size. */
|
||||||
|
R_TRY(this->QueryMetaDataSize(std::addressof(this->meta_data_size), storage));
|
||||||
|
|
||||||
|
/* Deallocate any old meta buffer and allocate a new one. */
|
||||||
|
this->DeallocateBuffer();
|
||||||
|
this->allocator = allocator;
|
||||||
|
this->buffer = reinterpret_cast<char *>(this->allocator->Allocate(this->meta_data_size));
|
||||||
|
R_UNLESS(this->buffer != nullptr, fs::ResultAllocationFailureInPartitionFileSystemMetaCore());
|
||||||
|
|
||||||
|
/* Perform regular initialization. */
|
||||||
|
return this->Initialize(storage, this->buffer, this->meta_data_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Format>
|
||||||
|
Result PartitionFileSystemMetaCore<Format>::Initialize(fs::IStorage *storage, void *meta, size_t meta_size) {
|
||||||
|
/* Validate size for header. */
|
||||||
|
R_UNLESS(meta_size >= sizeof(PartitionFileSystemHeader), fs::ResultInvalidSize());
|
||||||
|
|
||||||
|
/* Read the header. */
|
||||||
|
R_TRY(storage->Read(0, meta, sizeof(PartitionFileSystemHeader)));
|
||||||
|
|
||||||
|
/* Set and validate the header. */
|
||||||
|
this->header = reinterpret_cast<PartitionFileSystemHeader *>(meta);
|
||||||
|
R_UNLESS(crypto::IsSameBytes(this->header, Format::VersionSignature, sizeof(Format::VersionSignature)), ResultSignatureVerificationFailed());
|
||||||
|
|
||||||
|
/* Setup entries and name table. */
|
||||||
|
const size_t entries_size = this->header->entry_count * sizeof(typename Format::PartitionEntry);
|
||||||
|
this->entries = reinterpret_cast<PartitionEntry *>(reinterpret_cast<u8 *>(meta) + sizeof(PartitionFileSystemHeader));
|
||||||
|
this->name_table = reinterpret_cast<char *>(meta) + sizeof(PartitionFileSystemHeader) + entries_size;
|
||||||
|
|
||||||
|
/* Validate size for header + entries + name table. */
|
||||||
|
R_UNLESS(meta_size >= sizeof(PartitionFileSystemHeader) + entries_size + this->header->name_table_size, fs::ResultInvalidSize());
|
||||||
|
|
||||||
|
/* Read entries and name table. */
|
||||||
|
R_TRY(storage->Read(sizeof(PartitionFileSystemHeader), this->entries, entries_size + this->header->name_table_size));
|
||||||
|
|
||||||
|
/* Mark as initialized. */
|
||||||
|
this->initialized = true;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Format>
|
||||||
|
void PartitionFileSystemMetaCore<Format>::DeallocateBuffer() {
|
||||||
|
if (this->buffer != nullptr) {
|
||||||
|
AMS_ABORT_UNLESS(this->allocator != nullptr);
|
||||||
|
this->allocator->Deallocate(this->buffer, this->meta_data_size);
|
||||||
|
this->buffer = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Format>
|
||||||
|
const typename Format::PartitionEntry *PartitionFileSystemMetaCore<Format>::GetEntry(s32 index) const {
|
||||||
|
if (this->initialized && index >= 0 && index < this->header->entry_count) {
|
||||||
|
return std::addressof(this->entries[index]);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Format>
|
||||||
|
s32 PartitionFileSystemMetaCore<Format>::GetEntryCount() const {
|
||||||
|
if (this->initialized) {
|
||||||
|
return this->header->entry_count;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Format>
|
||||||
|
s32 PartitionFileSystemMetaCore<Format>::GetEntryIndex(const char *name) const {
|
||||||
|
if (this->initialized) {
|
||||||
|
for (s32 i = 0; i < this->header->entry_count; i++) {
|
||||||
|
const auto &entry = this->entries[i];
|
||||||
|
|
||||||
|
/* Name offset is invalid. */
|
||||||
|
if (entry.name_offset >= this->header->name_table_size) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compare to input name. */
|
||||||
|
const s32 max_count = this->header->name_table_size - entry.name_offset;
|
||||||
|
if (std::strncmp(std::addressof(this->name_table[entry.name_offset]), name, max_count) == 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Not found. */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Format>
|
||||||
|
const char *PartitionFileSystemMetaCore<Format>::GetEntryName(s32 index) const {
|
||||||
|
if (this->initialized && index < this->header->entry_count) {
|
||||||
|
return std::addressof(this->name_table[this->GetEntry(index)->name_offset]);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Format>
|
||||||
|
size_t PartitionFileSystemMetaCore<Format>::GetHeaderSize() const {
|
||||||
|
return sizeof(PartitionFileSystemHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Format>
|
||||||
|
size_t PartitionFileSystemMetaCore<Format>::GetMetaDataSize() const {
|
||||||
|
return this->meta_data_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Format>
|
||||||
|
Result PartitionFileSystemMetaCore<Format>::QueryMetaDataSize(size_t *out_size, fs::IStorage *storage) const {
|
||||||
|
AMS_ABORT_UNLESS(allocator != nullptr);
|
||||||
|
|
||||||
|
/* Read and validate the header. */
|
||||||
|
PartitionFileSystemHeader header;
|
||||||
|
R_TRY(storage->Read(0, std::addressof(header), sizeof(PartitionFileSystemHeader)));
|
||||||
|
R_UNLESS(crypto::IsSameBytes(std::addressof(header), Format::VersionSignature, sizeof(Format::VersionSignature)), ResultSignatureVerificationFailed());
|
||||||
|
|
||||||
|
/* Output size. */
|
||||||
|
*out_size = sizeof(PartitionFileSystemHeader) + header.entry_count * sizeof(typename Format::PartitionEntry) + header.name_table_size;
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
template class PartitionFileSystemMetaCore<impl::PartitionFileSystemFormat>;
|
||||||
|
|
||||||
|
}
|
@ -19,6 +19,7 @@
|
|||||||
#include <vapours/assert.hpp>
|
#include <vapours/assert.hpp>
|
||||||
#include <vapours/literals.hpp>
|
#include <vapours/literals.hpp>
|
||||||
|
|
||||||
|
#include <vapours/allocator.hpp>
|
||||||
#include <vapours/timespan.hpp>
|
#include <vapours/timespan.hpp>
|
||||||
#include <vapours/span.hpp>
|
#include <vapours/span.hpp>
|
||||||
|
|
||||||
|
58
libraries/libvapours/include/vapours/allocator.hpp
Normal file
58
libraries/libvapours/include/vapours/allocator.hpp
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020 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/common.hpp>
|
||||||
|
#include <vapours/assert.hpp>
|
||||||
|
|
||||||
|
namespace ams {
|
||||||
|
|
||||||
|
constexpr inline size_t DefaultAlignment = alignof(max_align_t);
|
||||||
|
|
||||||
|
using AllocateFunction = void *(*)(size_t);
|
||||||
|
using AllocateFunctionWithUserData = void *(*)(size_t, void *);
|
||||||
|
using AlignedAllocateFunction = void *(*)(size_t, size_t);
|
||||||
|
using AlignedAllocateFunctionWithUserData = void *(*)(size_t, size_t, void *);
|
||||||
|
using DeallocateFunction = void (*)(void *, size_t);
|
||||||
|
using FreeFunction = void (*)(void *);
|
||||||
|
using FreeFunctionWithUserData = void (*)(void *, void *);
|
||||||
|
|
||||||
|
class MemoryResource {
|
||||||
|
public:
|
||||||
|
ALWAYS_INLINE void *allocate(size_t size, size_t alignment = DefaultAlignment) {
|
||||||
|
return this->AllocateImpl(size, alignment);
|
||||||
|
}
|
||||||
|
ALWAYS_INLINE void deallocate(void *buffer, size_t size, size_t alignment = DefaultAlignment) {
|
||||||
|
this->DeallocateImpl(buffer, size, alignment);
|
||||||
|
}
|
||||||
|
ALWAYS_INLINE bool is_equal(const MemoryResource &resource) const {
|
||||||
|
return this->IsEqualImpl(resource);
|
||||||
|
}
|
||||||
|
ALWAYS_INLINE void *Allocate(size_t size, size_t alignment = DefaultAlignment) {
|
||||||
|
return this->AllocateImpl(size, alignment);
|
||||||
|
}
|
||||||
|
ALWAYS_INLINE void Deallocate(void *buffer, size_t size, size_t alignment = DefaultAlignment) {
|
||||||
|
this->DeallocateImpl(buffer, size, alignment);
|
||||||
|
}
|
||||||
|
ALWAYS_INLINE bool IsEqual(const MemoryResource &resource) const {
|
||||||
|
return this->IsEqualImpl(resource);
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
virtual void *AllocateImpl(size_t size, size_t alignment) = 0;
|
||||||
|
virtual void DeallocateImpl(void *buffer, size_t size, size_t alignment) = 0;
|
||||||
|
virtual bool IsEqualImpl(const MemoryResource &resource) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -75,6 +75,7 @@ namespace ams::fs {
|
|||||||
R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemB, 3248);
|
R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemB, 3248);
|
||||||
R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemC, 3249);
|
R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemC, 3249);
|
||||||
R_DEFINE_ERROR_RESULT(AllocationFailureInDirectorySaveDataFileSystem, 3321);
|
R_DEFINE_ERROR_RESULT(AllocationFailureInDirectorySaveDataFileSystem, 3321);
|
||||||
|
R_DEFINE_ERROR_RESULT(AllocationFailureInPartitionFileSystemMetaCore, 3350);
|
||||||
R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemD, 3352);
|
R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemD, 3352);
|
||||||
R_DEFINE_ERROR_RESULT(AllocationFailureInSubDirectoryFileSystem, 3355);
|
R_DEFINE_ERROR_RESULT(AllocationFailureInSubDirectoryFileSystem, 3355);
|
||||||
R_DEFINE_ERROR_RESULT(AllocationFailureInRegisterA, 3365);
|
R_DEFINE_ERROR_RESULT(AllocationFailureInRegisterA, 3365);
|
||||||
|
Loading…
Reference in New Issue
Block a user