mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-04-22 12:34:47 +00:00
fs: implement Mount(System)Data
This commit is contained in:
parent
d52c1ee850
commit
c7d9cd24a7
19 changed files with 2224 additions and 28 deletions
|
@ -23,6 +23,7 @@
|
|||
#include "fs/fs_remote_filesystem.hpp"
|
||||
#include "fs/fs_istorage.hpp"
|
||||
#include "fs/fs_substorage.hpp"
|
||||
#include "fs/fs_memory_storage.hpp"
|
||||
#include "fs/fs_remote_storage.hpp"
|
||||
#include "fs/fs_file_storage.hpp"
|
||||
#include "fs/fs_query_range.hpp"
|
||||
|
@ -30,7 +31,9 @@
|
|||
#include "fs/fs_mount.hpp"
|
||||
#include "fs/fs_path_tool.hpp"
|
||||
#include "fs/fs_path_utils.hpp"
|
||||
#include "fs/fs_rom_path_tool.hpp"
|
||||
#include "fs/fs_romfs_filesystem.hpp"
|
||||
#include "fs/fs_data.hpp"
|
||||
#include "fs/fs_system_data.hpp"
|
||||
#include "fs/fs_content_storage.hpp"
|
||||
#include "fs/fs_game_card.hpp"
|
||||
#include "fs/fs_sd_card.hpp"
|
||||
|
|
|
@ -19,3 +19,30 @@
|
|||
#include "../ncm.hpp"
|
||||
#include "../sf.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
struct Int64 {
|
||||
u32 low;
|
||||
u32 high;
|
||||
|
||||
constexpr ALWAYS_INLINE void Set(s64 v) {
|
||||
this->low = static_cast<u32>((v & static_cast<u64>(0x00000000FFFFFFFFul)) >> 0);
|
||||
this->high = static_cast<u32>((v & static_cast<u64>(0xFFFFFFFF00000000ul)) >> 32);
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE s64 Get() const {
|
||||
return (static_cast<s64>(this->high) << 32) | (static_cast<s64>(this->low));
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE Int64 &operator=(s64 v) {
|
||||
this->Set(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE operator s64() const {
|
||||
return this->Get();
|
||||
}
|
||||
};
|
||||
static_assert(std::is_pod<Int64>::value);
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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 "fs_common.hpp"
|
||||
|
||||
namespace ams::fs::impl {
|
||||
|
||||
Result QueryMountDataCacheSize(size_t *out, ncm::ProgramId data_id, ncm::StorageId storage_id);
|
||||
|
||||
Result MountData(const char *name, ncm::ProgramId data_id, ncm::StorageId storage_id);
|
||||
Result MountData(const char *name, ncm::ProgramId data_id, ncm::StorageId storage_id, void *cache_buffer, size_t cache_size);
|
||||
Result MountData(const char *name, ncm::ProgramId data_id, ncm::StorageId storage_id, void *cache_buffer, size_t cache_size, bool use_data_cache, bool use_path_cache);
|
||||
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* 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 "fs_dbm_rom_types.hpp"
|
||||
#include "fs_dbm_rom_path_tool.hpp"
|
||||
#include "fs_dbm_rom_key_value_storage.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
class HierarchicalRomFileTable {
|
||||
public:
|
||||
using Position = u32;
|
||||
|
||||
struct FindPosition {
|
||||
Position next_dir;
|
||||
Position next_file;
|
||||
};
|
||||
static_assert(std::is_pod<FindPosition>::value);
|
||||
|
||||
using DirectoryInfo = RomDirectoryInfo;
|
||||
using FileInfo = RomFileInfo;
|
||||
|
||||
static constexpr RomFileId ConvertToFileId(Position pos) {
|
||||
return static_cast<RomFileId>(pos);
|
||||
}
|
||||
private:
|
||||
static constexpr inline Position InvalidPosition = ~Position();
|
||||
static constexpr inline Position RootPosition = 0;
|
||||
static constexpr inline size_t ReservedDirectoryCount = 1;
|
||||
|
||||
static constexpr RomDirectoryId ConvertToDirectoryId(Position pos) {
|
||||
return static_cast<RomDirectoryId>(pos);
|
||||
}
|
||||
|
||||
static constexpr Position ConvertToPosition(RomDirectoryId id) {
|
||||
return static_cast<Position>(id);
|
||||
}
|
||||
|
||||
static_assert(std::is_same<RomDirectoryId, RomFileId>::value);
|
||||
|
||||
struct RomDirectoryEntry {
|
||||
Position next;
|
||||
Position dir;
|
||||
Position file;
|
||||
};
|
||||
static_assert(std::is_pod<RomDirectoryEntry>::value);
|
||||
|
||||
struct RomFileEntry {
|
||||
Position next;
|
||||
FileInfo info;
|
||||
};
|
||||
static_assert(std::is_pod<RomFileEntry>::value);
|
||||
|
||||
static constexpr inline u32 MaxKeyLength = RomPathTool::MaxPathLength;
|
||||
|
||||
template<typename ImplKeyType, typename ClientKeyType, typename ValueType>
|
||||
class EntryMapTable : public RomKeyValueStorage<ImplKeyType, ValueType, MaxKeyLength> {
|
||||
public:
|
||||
using ImplKey = ImplKeyType;
|
||||
using ClientKey = ClientKeyType;
|
||||
using Value = ValueType;
|
||||
using Position = HierarchicalRomFileTable::Position;
|
||||
using Base = RomKeyValueStorage<ImplKeyType, ValueType, MaxKeyLength>;
|
||||
public:
|
||||
Result Add(Position *out, const ClientKeyType &key, const Value &value) {
|
||||
return Base::AddImpl(out, key.key, key.Hash(), key.name.path, key.name.length * sizeof(RomPathChar), value);
|
||||
}
|
||||
|
||||
Result Get(Position *out_pos, Value *out_val, const ClientKeyType &key) {
|
||||
return Base::GetImpl(out_pos, out_val, key.key, key.Hash(), key.name.path, key.name.length * sizeof(RomPathChar));
|
||||
}
|
||||
|
||||
Result GetByPosition(ImplKey *out_key, Value *out_val, Position pos) {
|
||||
return Base::GetByPosition(out_key, out_val, pos);
|
||||
}
|
||||
|
||||
Result GetByPosition(ImplKey *out_key, Value *out_val, void *out_aux, size_t *out_aux_size, Position pos) {
|
||||
return Base::GetByPosition(out_key, out_val, out_aux, out_aux_size, pos);
|
||||
}
|
||||
|
||||
Result SetByPosition(Position pos, const Value &value) {
|
||||
return Base::SetByPosition(pos, value);
|
||||
}
|
||||
};
|
||||
|
||||
struct RomEntryKey {
|
||||
Position parent;
|
||||
|
||||
bool IsEqual(const RomEntryKey &rhs, const void *aux_lhs, size_t aux_lhs_size, const void *aux_rhs, size_t aux_rhs_size) const {
|
||||
if (this->parent != rhs.parent) {
|
||||
return false;
|
||||
}
|
||||
if (aux_lhs_size != aux_rhs_size) {
|
||||
return false;
|
||||
}
|
||||
return RomPathTool::IsEqualPath(reinterpret_cast<const RomPathChar *>(aux_lhs), reinterpret_cast<const RomPathChar *>(aux_rhs), aux_lhs_size / sizeof(RomPathChar));
|
||||
}
|
||||
};
|
||||
static_assert(std::is_pod<RomEntryKey>::value);
|
||||
|
||||
struct EntryKey {
|
||||
RomEntryKey key;
|
||||
RomPathTool::RomEntryName name;
|
||||
|
||||
constexpr u32 Hash() const {
|
||||
u32 hash = this->key.parent ^ 123456789;
|
||||
const RomPathChar *name = this->name.path;
|
||||
const RomPathChar *end = name + this->name.length;
|
||||
while (name < end) {
|
||||
const u32 cur = static_cast<u32>(static_cast<std::make_unsigned<RomPathChar>::type>(*(name++)));
|
||||
hash = ((hash >> 5) | (hash << 27)) ^ cur;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
static_assert(std::is_pod<EntryKey>::value);
|
||||
|
||||
using DirectoryEntryMapTable = EntryMapTable<RomEntryKey, EntryKey, RomDirectoryEntry>;
|
||||
using FileEntryMapTable = EntryMapTable<RomEntryKey, EntryKey, RomFileEntry>;
|
||||
private:
|
||||
DirectoryEntryMapTable dir_table;
|
||||
FileEntryMapTable file_table;
|
||||
public:
|
||||
static s64 QueryDirectoryEntryStorageSize(u32 count);
|
||||
static s64 QueryDirectoryEntryBucketStorageSize(s64 count);
|
||||
static s64 QueryFileEntryStorageSize(u32 count);
|
||||
static s64 QueryFileEntryBucketStorageSize(s64 count);
|
||||
|
||||
static Result Format(SubStorage dir_bucket, SubStorage file_bucket);
|
||||
public:
|
||||
HierarchicalRomFileTable();
|
||||
|
||||
constexpr u32 GetDirectoryEntryCount() const {
|
||||
return this->dir_table.GetEntryCount();
|
||||
}
|
||||
|
||||
constexpr u32 GetFileEntryCount() const {
|
||||
return this->file_table.GetEntryCount();
|
||||
}
|
||||
|
||||
Result Initialize(SubStorage dir_bucket, SubStorage dir_entry, SubStorage file_bucket, SubStorage file_entry);
|
||||
void Finalize();
|
||||
|
||||
Result CreateRootDirectory();
|
||||
Result CreateDirectory(RomDirectoryId *out, const RomPathChar *path, const DirectoryInfo &info);
|
||||
Result CreateFile(RomFileId *out, const RomPathChar *path, const FileInfo &info);
|
||||
Result ConvertPathToDirectoryId(RomDirectoryId *out, const RomPathChar *path);
|
||||
Result ConvertPathToFileId(RomFileId *out, const RomPathChar *path);
|
||||
|
||||
Result GetDirectoryInformation(DirectoryInfo *out, const RomPathChar *path);
|
||||
Result GetDirectoryInformation(DirectoryInfo *out, RomDirectoryId id);
|
||||
|
||||
Result OpenFile(FileInfo *out, const RomPathChar *path);
|
||||
Result OpenFile(FileInfo *out, RomFileId id);
|
||||
|
||||
Result FindOpen(FindPosition *out, const RomPathChar *path);
|
||||
Result FindOpen(FindPosition *out, RomDirectoryId id);
|
||||
|
||||
Result FindNextDirectory(RomPathChar *out, FindPosition *find, size_t length);
|
||||
Result FindNextFile(RomPathChar *out, FindPosition *find, size_t length);
|
||||
|
||||
Result QueryRomFileSystemSize(s64 *out_dir_entry_size, s64 *out_file_entry_size);
|
||||
private:
|
||||
Result GetGrandParent(Position *out_pos, EntryKey *out_dir_key, RomDirectoryEntry *out_dir_entry, Position pos, RomPathTool::RomEntryName name, const RomPathChar *path);
|
||||
|
||||
Result FindParentDirectoryRecursive(Position *out_pos, EntryKey *out_dir_key, RomDirectoryEntry *out_dir_entry, RomPathTool::PathParser *parser, const RomPathChar *path);
|
||||
|
||||
Result FindPathRecursive(EntryKey *out_key, RomDirectoryEntry *out_dir_entry, bool is_dir, const RomPathChar *path);
|
||||
Result FindDirectoryRecursive(EntryKey *out_key, RomDirectoryEntry *out_dir_entry, const RomPathChar *path);
|
||||
Result FindFileRecursive(EntryKey *out_key, RomDirectoryEntry *out_dir_entry, const RomPathChar *path);
|
||||
|
||||
Result CheckSameEntryExists(const EntryKey &key, Result if_exists);
|
||||
|
||||
Result GetDirectoryEntry(Position *out_pos, RomDirectoryEntry *out_entry, const EntryKey &key);
|
||||
Result GetDirectoryEntry(RomDirectoryEntry *out_entry, RomDirectoryId id);
|
||||
|
||||
Result GetFileEntry(Position *out_pos, RomFileEntry *out_entry, const EntryKey &key);
|
||||
Result GetFileEntry(RomFileEntry *out_entry, RomFileId id);
|
||||
|
||||
Result GetDirectoryInformation(DirectoryInfo *out, const EntryKey &key);
|
||||
|
||||
Result OpenFile(FileInfo *out, const EntryKey &key);
|
||||
|
||||
Result FindOpen(FindPosition *out, const EntryKey &key);
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,380 @@
|
|||
/*
|
||||
* 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 "fs_dbm_rom_types.hpp"
|
||||
#include "fs_substorage.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
template<typename KeyType, typename ValueType, size_t MaxAuxiliarySize>
|
||||
class RomKeyValueStorage {
|
||||
public:
|
||||
using Key = KeyType;
|
||||
using Value = ValueType;
|
||||
using Position = u32;
|
||||
using BucketIndex = s64;
|
||||
|
||||
struct FindIndex {
|
||||
BucketIndex ind;
|
||||
Position pos;
|
||||
};
|
||||
static_assert(std::is_pod<FindIndex>::value);
|
||||
private:
|
||||
static constexpr inline Position InvalidPosition = ~Position();
|
||||
|
||||
struct Element {
|
||||
Key key;
|
||||
Value value;
|
||||
Position next;
|
||||
u32 size;
|
||||
};
|
||||
static_assert(std::is_pod<Element>::value);
|
||||
private:
|
||||
s64 bucket_count;
|
||||
SubStorage bucket_storage;
|
||||
SubStorage kv_storage;
|
||||
s64 total_entry_size;
|
||||
u32 entry_count;
|
||||
public:
|
||||
static constexpr s64 QueryBucketStorageSize(s64 num) {
|
||||
return num * sizeof(Position);
|
||||
}
|
||||
|
||||
static constexpr s64 QueryBucketCount(s64 size) {
|
||||
return size / sizeof(Position);
|
||||
}
|
||||
|
||||
static constexpr s64 QueryKeyValueStorageSize(u32 num) {
|
||||
return num * sizeof(Element);
|
||||
}
|
||||
|
||||
static Result Format(SubStorage bucket, s64 count) {
|
||||
const Position pos = InvalidPosition;
|
||||
for (s64 i = 0; i < count; i++) {
|
||||
R_TRY(bucket.Write(i * sizeof(pos), std::addressof(pos), sizeof(pos)));
|
||||
}
|
||||
return ResultSuccess();
|
||||
}
|
||||
public:
|
||||
RomKeyValueStorage() : bucket_count(), bucket_storage(), kv_storage(), total_entry_size(), entry_count() { /* ... */ }
|
||||
|
||||
Result Initialize(const SubStorage &bucket, s64 count, const SubStorage &kv) {
|
||||
AMS_ASSERT(count > 0);
|
||||
this->bucket_storage = bucket;
|
||||
this->kv_storage = kv;
|
||||
this->bucket_count = count;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void Finalize() {
|
||||
this->bucket_storage = SubStorage();
|
||||
this->kv_storage = SubStorage();
|
||||
this->bucket_count = 0;
|
||||
}
|
||||
|
||||
s64 GetTotalEntrySize() const {
|
||||
return this->total_entry_size;
|
||||
}
|
||||
|
||||
Result GetFreeSize(s64 *out) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
s64 kv_size = 0;
|
||||
R_TRY(this->kv_storage.GetSize(std::addressof(kv_size)));
|
||||
*out = kv_size - this->total_entry_size;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
constexpr u32 GetEntryCount() const {
|
||||
return this->entry_count;
|
||||
}
|
||||
|
||||
Result Add(const Key &key, u32 hash_key, const void *aux, size_t aux_size, const Value &value) {
|
||||
AMS_ASSERT(aux != nullptr);
|
||||
AMS_ASSERT(aux_size <= MaxAuxiliarySize);
|
||||
Position pos;
|
||||
return this->AddImpl(std::addressof(pos), key, hash_key, aux, aux_size, value);
|
||||
}
|
||||
|
||||
Result Get(Value *out, const Key &key, u32 hash_key, const void *aux, size_t aux_size) {
|
||||
AMS_ASSERT(aux != nullptr);
|
||||
AMS_ASSERT(aux_size <= MaxAuxiliarySize);
|
||||
Position pos;
|
||||
return this->GetImpl(std::addressof(pos), out, key, hash_key, aux, aux_size);
|
||||
}
|
||||
|
||||
Result FindOpen(FindIndex *out) const {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
|
||||
out->ind = static_cast<BucketIndex>(-1);
|
||||
out->pos = InvalidPosition;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result FindNext(Key *out_key, Value *out_val, FindIndex *find) {
|
||||
AMS_ASSERT(out_key != nullptr);
|
||||
AMS_ASSERT(out_val != nullptr);
|
||||
AMS_ASSERT(find != nullptr);
|
||||
|
||||
BucketIndex ind = find->ind;
|
||||
R_UNLESS((ind < this->bucket_count) || ind == static_cast<BucketIndex>(-1), fs::ResultDbmFindKeyFinished());
|
||||
|
||||
s64 kv_size;
|
||||
R_TRY(this->kv_storage.GetSize(std::addressof(kv_size)));
|
||||
|
||||
while (true) {
|
||||
if (find->pos != InvalidPosition) {
|
||||
Element elem;
|
||||
R_TRY(this->ReadKeyValue(std::addressof(elem), find->pos));
|
||||
|
||||
AMS_ASSERT(elem.next == InvalidPosition || elem.next < kv_size);
|
||||
find->pos = elem.next;
|
||||
*out_key = elem.key;
|
||||
*out_val = elem.val;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
while (true) {
|
||||
ind++;
|
||||
if (ind == this->bucket_count) {
|
||||
find->ind = ind;
|
||||
find->pos = InvalidPosition;
|
||||
return fs::ResultDbmFindKeyFinished();
|
||||
}
|
||||
|
||||
Position pos;
|
||||
R_TRY(this->ReadBucket(std::addressof(pos), ind));
|
||||
AMS_ASSERT(pos == InvalidPosition || pos < kv_size);
|
||||
|
||||
if (pos != InvalidPosition) {
|
||||
find->ind = ind;
|
||||
find->pos = pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
protected:
|
||||
Result AddImpl(Position *out, const Key &key, u32 hash_key, const void *aux, size_t aux_size, const Value &value) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(aux != nullptr);
|
||||
AMS_ASSERT(this->bucket_count > 0);
|
||||
|
||||
{
|
||||
Position pos, prev_pos;
|
||||
Element elem;
|
||||
|
||||
const Result find_res = this->FindImpl(std::addressof(pos), std::addressof(prev_pos), std::addressof(elem), key, hash_key, aux, aux_size);
|
||||
R_UNLESS(R_FAILED(find_res), fs::ResultDbmAlreadyExists());
|
||||
R_UNLESS(fs::ResultDbmKeyNotFound::Includes(find_res), find_res);
|
||||
}
|
||||
|
||||
Position pos;
|
||||
R_TRY(this->AllocateEntry(std::addressof(pos), aux_size));
|
||||
|
||||
Position next_pos;
|
||||
R_TRY(this->LinkEntry(std::addressof(next_pos), pos, hash_key));
|
||||
|
||||
const Element elem = { key, value, next_pos, static_cast<u32>(aux_size) };
|
||||
R_TRY(this->WriteKeyValue(std::addressof(elem), pos, aux, aux_size));
|
||||
|
||||
*out = pos;
|
||||
this->entry_count++;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetImpl(Position *out_pos, Value *out_val, const Key &key, u32 hash_key, const void *aux, size_t aux_size) {
|
||||
AMS_ASSERT(out_pos != nullptr);
|
||||
AMS_ASSERT(out_val != nullptr);
|
||||
AMS_ASSERT(aux != nullptr);
|
||||
|
||||
Position pos, prev_pos;
|
||||
Element elem;
|
||||
R_TRY(this->FindImpl(std::addressof(pos), std::addressof(prev_pos), std::addressof(elem), key, hash_key, aux, aux_size));
|
||||
|
||||
*out_pos = pos;
|
||||
*out_val = elem.value;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetByPosition(Key *out_key, Value *out_val, Position pos) {
|
||||
AMS_ASSERT(out_key != nullptr);
|
||||
AMS_ASSERT(out_val != nullptr);
|
||||
|
||||
Element elem;
|
||||
R_TRY(this->ReadKeyValue(std::addressof(elem), pos));
|
||||
|
||||
*out_key = elem.key;
|
||||
*out_val = elem.value;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetByPosition(Key *out_key, Value *out_val, void *out_aux, size_t *out_aux_size, Position pos) {
|
||||
AMS_ASSERT(out_key != nullptr);
|
||||
AMS_ASSERT(out_val != nullptr);
|
||||
AMS_ASSERT(out_aux != nullptr);
|
||||
AMS_ASSERT(out_aux_size != nullptr);
|
||||
|
||||
Element elem;
|
||||
R_TRY(this->ReadKeyValue(std::addressof(elem), out_aux, out_aux_size, pos));
|
||||
|
||||
*out_key = elem.key;
|
||||
*out_val = elem.value;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result SetByPosition(Position pos, const Value &value) {
|
||||
Element elem;
|
||||
R_TRY(this->ReadKeyValue(std::addressof(elem), pos));
|
||||
elem.value = value;
|
||||
return this->WriteKeyValue(std::addressof(elem), pos, nullptr, 0);
|
||||
}
|
||||
private:
|
||||
BucketIndex HashToBucket(u32 hash_key) const {
|
||||
return hash_key % this->bucket_count;
|
||||
}
|
||||
|
||||
Result FindImpl(Position *out_pos, Position *out_prev, Element *out_elem, const Key &key, u32 hash_key, const void *aux, size_t aux_size) {
|
||||
AMS_ASSERT(out_pos != nullptr);
|
||||
AMS_ASSERT(out_prev != nullptr);
|
||||
AMS_ASSERT(out_elem != nullptr);
|
||||
AMS_ASSERT(aux != nullptr);
|
||||
AMS_ASSERT(this->bucket_count > 0);
|
||||
|
||||
*out_pos = 0;
|
||||
*out_prev = 0;
|
||||
|
||||
const BucketIndex ind = HashToBucket(hash_key);
|
||||
|
||||
Position cur;
|
||||
R_TRY(this->ReadBucket(std::addressof(cur), ind));
|
||||
|
||||
s64 kv_size;
|
||||
R_TRY(this->kv_storage.GetSize(std::addressof(kv_size)));
|
||||
AMS_ASSERT(cur == InvalidPosition || cur < kv_size);
|
||||
|
||||
R_UNLESS(cur != InvalidPosition, fs::ResultDbmKeyNotFound());
|
||||
|
||||
u8 *buf = static_cast<u8 *>(::ams::fs::impl::Allocate(MaxAuxiliarySize));
|
||||
R_UNLESS(buf != nullptr, fs::ResultAllocationFailureInDbmRomKeyValueStorage());
|
||||
ON_SCOPE_EXIT { ::ams::fs::impl::Deallocate(buf, MaxAuxiliarySize); };
|
||||
|
||||
while (true) {
|
||||
size_t cur_aux_size;
|
||||
R_TRY(this->ReadKeyValue(out_elem, buf, std::addressof(cur_aux_size), cur));
|
||||
|
||||
if (key.IsEqual(out_elem->key, aux, aux_size, buf, cur_aux_size)) {
|
||||
*out_pos = cur;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
*out_prev = cur;
|
||||
cur = out_elem->next;
|
||||
R_UNLESS(cur != InvalidPosition, fs::ResultDbmKeyNotFound());
|
||||
}
|
||||
}
|
||||
|
||||
Result AllocateEntry(Position *out, size_t aux_size) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
|
||||
s64 kv_size;
|
||||
R_TRY(this->kv_storage.GetSize(std::addressof(kv_size)));
|
||||
const size_t end_pos = this->total_entry_size + sizeof(Element) + aux_size;
|
||||
R_UNLESS(end_pos <= static_cast<size_t>(kv_size), fs::ResultDbmKeyFull());
|
||||
|
||||
*out = static_cast<Position>(this->total_entry_size);
|
||||
|
||||
this->total_entry_size = util::AlignUp(static_cast<s64>(end_pos), s64(4));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result LinkEntry(Position *out, Position pos, u32 hash_key) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
|
||||
const BucketIndex ind = HashToBucket(hash_key);
|
||||
|
||||
Position next;
|
||||
R_TRY(this->ReadBucket(std::addressof(next), ind));
|
||||
|
||||
s64 kv_size;
|
||||
R_TRY(this->kv_storage.GetSize(std::addressof(kv_size)));
|
||||
AMS_ASSERT(next == InvalidPosition || next < kv_size);
|
||||
|
||||
R_TRY(this->WriteBucket(pos, ind));
|
||||
|
||||
*out = next;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ReadBucket(Position *out, BucketIndex ind) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(ind < this->bucket_count);
|
||||
|
||||
const s64 offset = ind * sizeof(Position);
|
||||
return this->bucket_storage.Read(offset, out, sizeof(*out));
|
||||
}
|
||||
|
||||
Result WriteBucket(Position pos, BucketIndex ind) {
|
||||
AMS_ASSERT(ind < this->bucket_count);
|
||||
|
||||
const s64 offset = ind * sizeof(Position);
|
||||
return this->bucket_storage.Write(offset, std::addressof(pos), sizeof(pos));
|
||||
}
|
||||
|
||||
Result ReadKeyValue(Element *out, Position pos) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
|
||||
s64 kv_size;
|
||||
R_TRY(this->kv_storage.GetSize(std::addressof(kv_size)));
|
||||
AMS_ASSERT(pos < kv_size);
|
||||
|
||||
return this->kv_storage.Read(pos, out, sizeof(*out));
|
||||
}
|
||||
|
||||
Result ReadKeyValue(Element *out, void *out_aux, size_t *out_aux_size, Position pos) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(out_aux != nullptr);
|
||||
AMS_ASSERT(out_aux_size != nullptr);
|
||||
|
||||
R_TRY(this->ReadKeyValue(out, pos));
|
||||
|
||||
*out_aux_size = out->size;
|
||||
if (out->size > 0) {
|
||||
R_TRY(this->kv_storage.Read(pos + sizeof(*out), out_aux, out->size));
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result WriteKeyValue(const Element *elem, Position pos, const void *aux, size_t aux_size) {
|
||||
AMS_ASSERT(elem != nullptr);
|
||||
AMS_ASSERT(aux != nullptr);
|
||||
|
||||
s64 kv_size;
|
||||
R_TRY(this->kv_storage.GetSize(std::addressof(kv_size)));
|
||||
AMS_ASSERT(pos < kv_size);
|
||||
|
||||
R_TRY(this->kv_storage.Write(pos, elem, sizeof(*elem)));
|
||||
|
||||
if (aux != nullptr && aux_size > 0) {
|
||||
R_TRY(this->kv_storage.Write(pos + sizeof(*elem), aux, aux_size));
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "fs_rom_types.hpp"
|
||||
#include "fs_dbm_rom_types.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
|
@ -43,8 +43,8 @@ namespace ams::fs {
|
|||
static_assert(std::is_pod<RomDirectoryInfo>::value);
|
||||
|
||||
struct RomFileInfo {
|
||||
s64 offset;
|
||||
s64 size;
|
||||
Int64 offset;
|
||||
Int64 size;
|
||||
};
|
||||
static_assert(std::is_pod<RomFileInfo>::value);
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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 "impl/fs_newable.hpp"
|
||||
#include "fs_istorage.hpp"
|
||||
#include "fs_query_range.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
class MemoryStorage : public ::ams::fs::IStorage, public ::ams::fs::impl::Newable {
|
||||
private:
|
||||
u8 * const buf;
|
||||
const s64 size;
|
||||
public:
|
||||
MemoryStorage(void *b, s64 sz) : buf(static_cast<u8 *>(b)), size(sz) { /* .. */ }
|
||||
public:
|
||||
virtual Result Read(s64 offset, void *buffer, size_t size) override {
|
||||
R_UNLESS(size != 0, ResultSuccess());
|
||||
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
|
||||
R_UNLESS(IStorage::IsRangeValid(offset, size, this->size), fs::ResultOutOfRange());
|
||||
std::memcpy(buffer, this->buf + offset, size);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
virtual Result Write(s64 offset, const void *buffer, size_t size) override{
|
||||
R_UNLESS(size != 0, ResultSuccess());
|
||||
R_UNLESS(buffer != nullptr, fs::ResultNullptrArgument());
|
||||
R_UNLESS(IStorage::IsRangeValid(offset, size, this->size), fs::ResultOutOfRange());
|
||||
std::memcpy(this->buf + offset, buffer, size);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
virtual Result Flush() override {
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
virtual Result GetSize(s64 *out) override {
|
||||
*out = this->size;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
virtual Result OperateRange(void *dst, size_t dst_size, OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override {
|
||||
switch (op_id) {
|
||||
case OperationId::InvalidateCache:
|
||||
return ResultSuccess();
|
||||
case OperationId::QueryRange:
|
||||
R_UNLESS(dst != nullptr, fs::ResultNullptrArgument());
|
||||
R_UNLESS(dst_size == sizeof(QueryRangeInfo), fs::ResultInvalidSize());
|
||||
reinterpret_cast<QueryRangeInfo *>(dst)->Clear();
|
||||
return ResultSuccess();
|
||||
default:
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -16,10 +16,11 @@
|
|||
#pragma once
|
||||
#include "fs_common.hpp"
|
||||
#include "fs_istorage.hpp"
|
||||
#include "impl/fs_newable.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
class RemoteStorage : public IStorage {
|
||||
class RemoteStorage : public IStorage, public impl::Newable {
|
||||
private:
|
||||
std::unique_ptr<::FsStorage, impl::Deleter> base_storage;
|
||||
public:
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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 "fs_common.hpp"
|
||||
#include "impl/fs_newable.hpp"
|
||||
#include "fsa/fs_ifile.hpp"
|
||||
#include "fsa/fs_idirectory.hpp"
|
||||
#include "fsa/fs_ifilesystem.hpp"
|
||||
#include "fs_dbm_hierarchical_rom_file_table.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
class RomFsFileSystem : public fsa::IFileSystem, public impl::Newable {
|
||||
NON_COPYABLE(RomFsFileSystem);
|
||||
public:
|
||||
using RomFileTable = HierarchicalRomFileTable;
|
||||
private:
|
||||
RomFileTable rom_file_table;
|
||||
IStorage *base_storage;
|
||||
std::unique_ptr<IStorage> unique_storage;
|
||||
std::unique_ptr<IStorage> dir_bucket_storage;
|
||||
std::unique_ptr<IStorage> dir_entry_storage;
|
||||
std::unique_ptr<IStorage> file_bucket_storage;
|
||||
std::unique_ptr<IStorage> file_entry_storage;
|
||||
s64 entry_size;
|
||||
private:
|
||||
Result GetFileInfo(RomFileTable::FileInfo *out, const char *path);
|
||||
public:
|
||||
static Result GetRequiredWorkingMemorySize(size_t *out, IStorage *storage);
|
||||
public:
|
||||
RomFsFileSystem();
|
||||
virtual ~RomFsFileSystem() override;
|
||||
|
||||
Result Initialize(IStorage *base, void *work, size_t work_size, bool use_cache);
|
||||
Result Initialize(std::unique_ptr<IStorage>&& base, void *work, size_t work_size, bool use_cache);
|
||||
|
||||
IStorage *GetBaseStorage();
|
||||
RomFileTable *GetRomFileTable();
|
||||
Result GetFileBaseOffset(s64 *out, const char *path);
|
||||
public:
|
||||
virtual Result CreateFileImpl(const char *path, s64 size, int flags) override;
|
||||
virtual Result DeleteFileImpl(const char *path) override;
|
||||
virtual Result CreateDirectoryImpl(const char *path) override;
|
||||
virtual Result DeleteDirectoryImpl(const char *path) override;
|
||||
virtual Result DeleteDirectoryRecursivelyImpl(const char *path) override;
|
||||
virtual Result RenameFileImpl(const char *old_path, const char *new_path) override;
|
||||
virtual Result RenameDirectoryImpl(const char *old_path, const char *new_path) override;
|
||||
virtual Result GetEntryTypeImpl(fs::DirectoryEntryType *out, const char *path) override;
|
||||
virtual Result OpenFileImpl(std::unique_ptr<fs::fsa::IFile> *out_file, const char *path, fs::OpenMode mode) override;
|
||||
virtual Result OpenDirectoryImpl(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const char *path, fs::OpenDirectoryMode mode) override;
|
||||
virtual Result CommitImpl() override;
|
||||
virtual Result GetFreeSpaceSizeImpl(s64 *out, const char *path) override;
|
||||
virtual Result GetTotalSpaceSizeImpl(s64 *out, const char *path) override;
|
||||
virtual Result CleanDirectoryRecursivelyImpl(const char *path) override;
|
||||
|
||||
/* These aren't accessible as commands. */
|
||||
virtual Result CommitProvisionallyImpl(s64 counter) override;
|
||||
virtual Result RollbackImpl() override;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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 "fs_common.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
Result QueryMountSystemDataCacheSize(size_t *out, ncm::ProgramId data_id);
|
||||
|
||||
Result MountSystemData(const char *name, ncm::ProgramId data_id);
|
||||
Result MountSystemData(const char *name, ncm::ProgramId data_id, void *cache_buffer, size_t cache_size);
|
||||
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
#pragma once
|
||||
#include "../fs_common.hpp"
|
||||
#include "../fs_file.hpp"
|
||||
#include "../fs_filesystem.hpp"
|
||||
#include "../fs_operate_range.hpp"
|
||||
|
||||
namespace ams::fs::fsa {
|
||||
|
@ -82,7 +83,25 @@ namespace ams::fs::fsa {
|
|||
/* TODO: This is a hack to allow the mitm API to work. Find a better way? */
|
||||
virtual sf::cmif::DomainObjectId GetDomainObjectId() const = 0;
|
||||
protected:
|
||||
/* ...? */
|
||||
Result DryRead(size_t *out, s64 offset, size_t size, const ReadOption &option, fs::OpenMode mode) {
|
||||
R_UNLESS((mode & fs::OpenMode_Read) != 0, fs::ResultInvalidOperationForOpenMode());
|
||||
|
||||
s64 file_size = 0;
|
||||
R_TRY(this->GetSize(std::addressof(file_size)));
|
||||
R_UNLESS(offset <= file_size, fs::ResultOutOfRange());
|
||||
|
||||
const size_t readable_size = file_size - offset;
|
||||
*out = std::min(readable_size, size);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result DrySetSize(s64 size, fs::OpenMode mode) {
|
||||
R_UNLESS((mode & fs::OpenMode_Write) != 0, fs::ResultInvalidOperationForOpenMode());
|
||||
|
||||
AMS_ASSERT(size >= 0);
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
private:
|
||||
virtual Result ReadImpl(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) = 0;
|
||||
virtual Result GetSizeImpl(s64 *out) = 0;
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace ams::fs::fsa {
|
|||
|
||||
Result Register(const char *name, std::unique_ptr<IFileSystem> &&fs);
|
||||
Result Register(const char *name, std::unique_ptr<IFileSystem> &&fs, std::unique_ptr<ICommonMountNameGenerator> &&generator);
|
||||
/* TODO: Register with cache settings */
|
||||
Result Register(const char *name, std::unique_ptr<IFileSystem> &&fs, std::unique_ptr<ICommonMountNameGenerator> &&generator, bool use_data_cache, bool use_path_cache, bool multi_commit_supported);
|
||||
|
||||
void Unregister(const char *name);
|
||||
}
|
||||
|
|
89
libraries/libstratosphere/source/fs/fs_data.cpp
Normal file
89
libraries/libstratosphere/source/fs/fs_data.cpp
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* 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>
|
||||
#include "fsa/fs_mount_utils.hpp"
|
||||
|
||||
namespace ams::fs::impl {
|
||||
|
||||
namespace {
|
||||
|
||||
Result OpenDataStorageByDataId(std::unique_ptr<ams::fs::IStorage> *out, ncm::ProgramId data_id, ncm::StorageId storage_id) {
|
||||
/* Open storage using libnx bindings. */
|
||||
::FsStorage s;
|
||||
R_TRY_CATCH(fsOpenDataStorageByDataId(std::addressof(s), static_cast<u64>(data_id), static_cast<::NcmStorageId>(storage_id))) {
|
||||
R_CONVERT(ncm::ResultContentMetaNotFound, fs::ResultTargetNotFound());
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
std::unique_ptr<fs::IStorage> storage(new RemoteStorage(s));
|
||||
R_UNLESS(storage != nullptr, fs::ResultAllocationFailureInDataA());
|
||||
|
||||
*out = std::move(storage);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result MountDataImpl(const char *name, ncm::ProgramId data_id, ncm::StorageId storage_id, void *cache_buffer, size_t cache_size, bool use_cache, bool use_data_cache, bool use_path_cache) {
|
||||
std::unique_ptr<fs::IStorage> storage;
|
||||
R_TRY(OpenDataStorageByDataId(std::addressof(storage), data_id, storage_id));
|
||||
|
||||
std::unique_ptr<RomFsFileSystem> fs(new RomFsFileSystem());
|
||||
R_UNLESS(fs != nullptr, fs::ResultAllocationFailureInDataB());
|
||||
R_TRY(fs->Initialize(std::move(storage), cache_buffer, cache_size, use_cache));
|
||||
|
||||
return fsa::Register(name, std::move(fs), nullptr, use_data_cache, use_path_cache, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Result QueryMountDataCacheSize(size_t *out, ncm::ProgramId data_id, ncm::StorageId storage_id) {
|
||||
R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
|
||||
|
||||
std::unique_ptr<fs::IStorage> storage;
|
||||
R_TRY(OpenDataStorageByDataId(std::addressof(storage), data_id, storage_id));
|
||||
|
||||
size_t size = 0;
|
||||
R_TRY(RomFsFileSystem::GetRequiredWorkingMemorySize(std::addressof(size), storage.get()));
|
||||
|
||||
constexpr size_t MinimumCacheSize = 32;
|
||||
*out = std::max(size, MinimumCacheSize);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result MountData(const char *name, ncm::ProgramId data_id, ncm::StorageId storage_id) {
|
||||
/* Validate the mount name. */
|
||||
R_TRY(impl::CheckMountName(name));
|
||||
|
||||
return MountDataImpl(name, data_id, storage_id, nullptr, 0, false, false, false);
|
||||
}
|
||||
|
||||
Result MountData(const char *name, ncm::ProgramId data_id, ncm::StorageId storage_id, void *cache_buffer, size_t cache_size) {
|
||||
/* Validate the mount name. */
|
||||
R_TRY(impl::CheckMountName(name));
|
||||
|
||||
R_UNLESS(cache_buffer != nullptr, fs::ResultNullptrArgument());
|
||||
|
||||
return MountDataImpl(name, data_id, storage_id, cache_buffer, cache_size, true, false, false);
|
||||
}
|
||||
|
||||
Result MountData(const char *name, ncm::ProgramId data_id, ncm::StorageId storage_id, void *cache_buffer, size_t cache_size, bool use_data_cache, bool use_path_cache) {
|
||||
/* Validate the mount name. */
|
||||
R_TRY(impl::CheckMountName(name));
|
||||
|
||||
R_UNLESS(cache_buffer != nullptr, fs::ResultNullptrArgument());
|
||||
|
||||
return MountDataImpl(name, data_id, storage_id, cache_buffer, cache_size, true, use_data_cache, use_path_cache);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,578 @@
|
|||
/*
|
||||
* 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::fs {
|
||||
|
||||
s64 HierarchicalRomFileTable::QueryDirectoryEntryStorageSize(u32 count) {
|
||||
const size_t real_count = count + ReservedDirectoryCount;
|
||||
return DirectoryEntryMapTable::QueryKeyValueStorageSize(real_count) + real_count * (RomPathTool::MaxPathLength + 1) * sizeof(RomPathChar);
|
||||
}
|
||||
|
||||
s64 HierarchicalRomFileTable::QueryDirectoryEntryBucketStorageSize(s64 count) {
|
||||
return DirectoryEntryMapTable::QueryBucketStorageSize(count);
|
||||
}
|
||||
|
||||
s64 HierarchicalRomFileTable::QueryFileEntryStorageSize(u32 count) {
|
||||
return FileEntryMapTable::QueryKeyValueStorageSize(count) + count * (RomPathTool::MaxPathLength + 1) * sizeof(RomPathChar);
|
||||
}
|
||||
|
||||
s64 HierarchicalRomFileTable::QueryFileEntryBucketStorageSize(s64 count) {
|
||||
return FileEntryMapTable::QueryBucketStorageSize(count);
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::Format(SubStorage dir_bucket, SubStorage file_bucket) {
|
||||
s64 dir_bucket_size;
|
||||
R_TRY(dir_bucket.GetSize(std::addressof(dir_bucket_size)));
|
||||
R_TRY(DirectoryEntryMapTable::Format(dir_bucket, DirectoryEntryMapTable::QueryBucketCount(dir_bucket_size)));
|
||||
|
||||
s64 file_bucket_size;
|
||||
R_TRY(file_bucket.GetSize(std::addressof(file_bucket_size)));
|
||||
R_TRY(FileEntryMapTable::Format(file_bucket, FileEntryMapTable::QueryBucketCount(file_bucket_size)));
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
HierarchicalRomFileTable::HierarchicalRomFileTable() { /* ... */ }
|
||||
|
||||
Result HierarchicalRomFileTable::Initialize(SubStorage dir_bucket, SubStorage dir_entry, SubStorage file_bucket, SubStorage file_entry) {
|
||||
s64 dir_bucket_size;
|
||||
R_TRY(dir_bucket.GetSize(std::addressof(dir_bucket_size)));
|
||||
R_TRY(this->dir_table.Initialize(dir_bucket, DirectoryEntryMapTable::QueryBucketCount(dir_bucket_size), dir_entry));
|
||||
|
||||
s64 file_bucket_size;
|
||||
R_TRY(file_bucket.GetSize(std::addressof(file_bucket_size)));
|
||||
R_TRY(this->file_table.Initialize(file_bucket, FileEntryMapTable::QueryBucketCount(file_bucket_size), file_entry));
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void HierarchicalRomFileTable::Finalize() {
|
||||
this->dir_table.Finalize();
|
||||
this->file_table.Finalize();
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::CreateRootDirectory() {
|
||||
Position root_pos = RootPosition;
|
||||
EntryKey root_key = {};
|
||||
root_key.key.parent = root_pos;
|
||||
RomPathTool::InitializeRomEntryName(std::addressof(root_key.name));
|
||||
RomDirectoryEntry root_entry = {
|
||||
.next = InvalidPosition,
|
||||
.dir = InvalidPosition,
|
||||
.file = InvalidPosition,
|
||||
};
|
||||
return this->dir_table.Add(std::addressof(root_pos), root_key, root_entry);
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::CreateDirectory(RomDirectoryId *out, const RomPathChar *path, const DirectoryInfo &info) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
RomDirectoryEntry parent_entry = {};
|
||||
EntryKey new_key = {};
|
||||
R_TRY(this->FindDirectoryRecursive(std::addressof(new_key), std::addressof(parent_entry), path));
|
||||
|
||||
R_TRY(this->CheckSameEntryExists(new_key, fs::ResultDbmAlreadyExists()));
|
||||
|
||||
RomDirectoryEntry new_entry = {
|
||||
.next = InvalidPosition,
|
||||
.dir = InvalidPosition,
|
||||
.file = InvalidPosition,
|
||||
};
|
||||
|
||||
Position new_pos = 0;
|
||||
R_TRY_CATCH(this->dir_table.Add(std::addressof(new_pos), new_key, new_entry)) {
|
||||
R_CONVERT(fs::ResultDbmKeyFull, fs::ResultDbmDirectoryEntryFull())
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
*out = ConvertToDirectoryId(new_pos);
|
||||
|
||||
if (parent_entry.dir == InvalidPosition) {
|
||||
parent_entry.dir = new_pos;
|
||||
|
||||
R_TRY(this->dir_table.SetByPosition(new_key.key.parent, parent_entry));
|
||||
} else {
|
||||
Position cur_pos = parent_entry.dir;
|
||||
while (true) {
|
||||
RomEntryKey cur_key = {};
|
||||
RomDirectoryEntry cur_entry = {};
|
||||
R_TRY(this->dir_table.GetByPosition(std::addressof(cur_key), std::addressof(cur_entry), cur_pos));
|
||||
|
||||
if (cur_entry.next == InvalidPosition) {
|
||||
cur_entry.next = new_pos;
|
||||
|
||||
R_TRY(this->dir_table.SetByPosition(cur_pos, cur_entry));
|
||||
break;
|
||||
}
|
||||
|
||||
cur_pos = cur_entry.next;
|
||||
}
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::CreateFile(RomFileId *out, const RomPathChar *path, const FileInfo &info) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
RomDirectoryEntry parent_entry = {};
|
||||
EntryKey new_key = {};
|
||||
R_TRY(this->FindFileRecursive(std::addressof(new_key), std::addressof(parent_entry), path));
|
||||
|
||||
R_TRY(this->CheckSameEntryExists(new_key, fs::ResultDbmAlreadyExists()));
|
||||
|
||||
RomFileEntry new_entry = {
|
||||
.next = InvalidPosition,
|
||||
.info = info,
|
||||
};
|
||||
|
||||
Position new_pos = 0;
|
||||
R_TRY_CATCH(this->file_table.Add(std::addressof(new_pos), new_key, new_entry)) {
|
||||
R_CONVERT(fs::ResultDbmKeyFull, fs::ResultDbmFileEntryFull())
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
*out = ConvertToFileId(new_pos);
|
||||
|
||||
if (parent_entry.file == InvalidPosition) {
|
||||
parent_entry.file = new_pos;
|
||||
|
||||
R_TRY(this->dir_table.SetByPosition(new_key.key.parent, parent_entry));
|
||||
} else {
|
||||
Position cur_pos = parent_entry.file;
|
||||
while (true) {
|
||||
RomEntryKey cur_key = {};
|
||||
RomFileEntry cur_entry = {};
|
||||
R_TRY(this->file_table.GetByPosition(std::addressof(cur_key), std::addressof(cur_entry), cur_pos));
|
||||
|
||||
if (cur_entry.next == InvalidPosition) {
|
||||
cur_entry.next = new_pos;
|
||||
|
||||
R_TRY(this->file_table.SetByPosition(cur_pos, cur_entry));
|
||||
break;
|
||||
}
|
||||
|
||||
cur_pos = cur_entry.next;
|
||||
}
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::ConvertPathToDirectoryId(RomDirectoryId *out, const RomPathChar *path) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
RomDirectoryEntry parent_entry = {};
|
||||
EntryKey key = {};
|
||||
R_TRY(this->FindDirectoryRecursive(std::addressof(key), std::addressof(parent_entry), path));
|
||||
|
||||
Position pos = 0;
|
||||
RomDirectoryEntry entry = {};
|
||||
R_TRY(this->GetDirectoryEntry(std::addressof(pos), std::addressof(entry), key));
|
||||
|
||||
*out = ConvertToDirectoryId(pos);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::ConvertPathToFileId(RomFileId *out, const RomPathChar *path) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
RomDirectoryEntry parent_entry = {};
|
||||
EntryKey key = {};
|
||||
R_TRY(this->FindDirectoryRecursive(std::addressof(key), std::addressof(parent_entry), path));
|
||||
|
||||
Position pos = 0;
|
||||
RomFileEntry entry = {};
|
||||
R_TRY(this->GetFileEntry(std::addressof(pos), std::addressof(entry), key));
|
||||
|
||||
*out = ConvertToFileId(pos);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::GetDirectoryInformation(DirectoryInfo *out, const RomPathChar *path) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
RomDirectoryEntry parent_entry = {};
|
||||
EntryKey key = {};
|
||||
R_TRY(this->FindDirectoryRecursive(std::addressof(key), std::addressof(parent_entry), path));
|
||||
|
||||
return this->GetDirectoryInformation(out, key);
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::GetDirectoryInformation(DirectoryInfo *out, RomDirectoryId id) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
|
||||
RomDirectoryEntry entry = {};
|
||||
R_TRY(this->GetDirectoryEntry(std::addressof(entry), id));
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::OpenFile(FileInfo *out, const RomPathChar *path) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
RomDirectoryEntry parent_entry = {};
|
||||
EntryKey key = {};
|
||||
R_TRY(this->FindFileRecursive(std::addressof(key), std::addressof(parent_entry), path));
|
||||
|
||||
return this->OpenFile(out, key);
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::OpenFile(FileInfo *out, RomFileId id) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
|
||||
RomFileEntry entry = {};
|
||||
R_TRY(this->GetFileEntry(std::addressof(entry), id));
|
||||
|
||||
*out = entry.info;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::FindOpen(FindPosition *out, const RomPathChar *path) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
RomDirectoryEntry parent_entry = {};
|
||||
EntryKey key = {};
|
||||
R_TRY(this->FindDirectoryRecursive(std::addressof(key), std::addressof(parent_entry), path));
|
||||
|
||||
return this->FindOpen(out, key);
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::FindOpen(FindPosition *out, RomDirectoryId id) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
|
||||
out->next_dir = InvalidPosition;
|
||||
out->next_file = InvalidPosition;
|
||||
|
||||
RomDirectoryEntry entry = {};
|
||||
R_TRY(this->GetDirectoryEntry(std::addressof(entry), id));
|
||||
|
||||
out->next_dir = entry.dir;
|
||||
out->next_file = entry.file;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::FindNextDirectory(RomPathChar *out, FindPosition *find, size_t length) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(find != nullptr);
|
||||
AMS_ASSERT(length > RomPathTool::MaxPathLength);
|
||||
|
||||
R_UNLESS(find->next_dir != InvalidPosition, fs::ResultDbmFindFinished());
|
||||
|
||||
RomEntryKey key = {};
|
||||
RomDirectoryEntry entry = {};
|
||||
size_t aux_size = 0;
|
||||
R_TRY(this->dir_table.GetByPosition(std::addressof(key), std::addressof(entry), out, std::addressof(aux_size), find->next_dir));
|
||||
AMS_ASSERT(aux_size / sizeof(RomPathChar) <= RomPathTool::MaxPathLength);
|
||||
|
||||
out[aux_size / sizeof(RomPathChar)] = RomStringTraits::NullTerminator;
|
||||
|
||||
find->next_dir = entry.next;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::FindNextFile(RomPathChar *out, FindPosition *find, size_t length) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(find != nullptr);
|
||||
AMS_ASSERT(length > RomPathTool::MaxPathLength);
|
||||
|
||||
R_UNLESS(find->next_file != InvalidPosition, fs::ResultDbmFindFinished());
|
||||
|
||||
RomEntryKey key = {};
|
||||
RomFileEntry entry = {};
|
||||
size_t aux_size = 0;
|
||||
R_TRY(this->file_table.GetByPosition(std::addressof(key), std::addressof(entry), out, std::addressof(aux_size), find->next_file));
|
||||
AMS_ASSERT(aux_size / sizeof(RomPathChar) <= RomPathTool::MaxPathLength);
|
||||
|
||||
out[aux_size / sizeof(RomPathChar)] = RomStringTraits::NullTerminator;
|
||||
|
||||
find->next_file = entry.next;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::QueryRomFileSystemSize(s64 *out_dir_entry_size, s64 *out_file_entry_size) {
|
||||
AMS_ASSERT(out_dir_entry_size != nullptr);
|
||||
AMS_ASSERT(out_file_entry_size != nullptr);
|
||||
|
||||
*out_dir_entry_size = this->dir_table.GetTotalEntrySize();
|
||||
*out_file_entry_size = this->file_table.GetTotalEntrySize();
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::GetGrandParent(Position *out_pos, EntryKey *out_dir_key, RomDirectoryEntry *out_dir_entry, Position pos, RomPathTool::RomEntryName name, const RomPathChar *path) {
|
||||
AMS_ASSERT(out_pos != nullptr);
|
||||
AMS_ASSERT(out_dir_key != nullptr);
|
||||
AMS_ASSERT(out_dir_entry != nullptr);
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
RomEntryKey gp_key = {};
|
||||
RomDirectoryEntry gp_entry = {};
|
||||
R_TRY(this->dir_table.GetByPosition(std::addressof(gp_key), std::addressof(gp_entry), pos));
|
||||
out_dir_key->key.parent = gp_key.parent;
|
||||
|
||||
R_TRY(RomPathTool::GetParentDirectoryName(std::addressof(out_dir_key->name), name, path));
|
||||
|
||||
R_TRY(this->GetDirectoryEntry(out_pos, out_dir_entry, *out_dir_key));
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::FindParentDirectoryRecursive(Position *out_pos, EntryKey *out_dir_key, RomDirectoryEntry *out_dir_entry, RomPathTool::PathParser *parser, const RomPathChar *path) {
|
||||
AMS_ASSERT(out_pos != nullptr);
|
||||
AMS_ASSERT(out_dir_key != nullptr);
|
||||
AMS_ASSERT(out_dir_entry != nullptr);
|
||||
AMS_ASSERT(parser != nullptr);
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
Position dir_pos = RootPosition;
|
||||
EntryKey dir_key = {};
|
||||
RomDirectoryEntry dir_entry = {};
|
||||
dir_key.key.parent = RootPosition;
|
||||
|
||||
R_TRY(parser->GetNextDirectoryName(std::addressof(dir_key.name)));
|
||||
R_TRY(this->GetDirectoryEntry(std::addressof(dir_pos), std::addressof(dir_entry), dir_key));
|
||||
|
||||
Position parent_pos = dir_pos;
|
||||
while (!parser->IsFinished()) {
|
||||
EntryKey old_key = dir_key;
|
||||
|
||||
R_TRY(parser->GetNextDirectoryName(std::addressof(dir_key.name)));
|
||||
|
||||
if (RomPathTool::IsCurrentDirectory(dir_key.name)) {
|
||||
dir_key = old_key;
|
||||
continue;
|
||||
} else if (RomPathTool::IsParentDirectory(dir_key.name)) {
|
||||
R_UNLESS(parent_pos != RootPosition, fs::ResultDirectoryUnobtainable());
|
||||
|
||||
R_TRY(this->GetGrandParent(std::addressof(parent_pos), std::addressof(dir_key), std::addressof(dir_entry), dir_key.key.parent, dir_key.name, path));
|
||||
} else {
|
||||
dir_key.key.parent = parent_pos;
|
||||
R_TRY_CATCH(this->GetDirectoryEntry(std::addressof(dir_pos), std::addressof(dir_entry), dir_key)) {
|
||||
R_CONVERT(fs::ResultDbmInvalidOperation, fs::ResultDbmNotFound())
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
parent_pos = dir_pos;
|
||||
}
|
||||
}
|
||||
|
||||
*out_pos = parent_pos;
|
||||
*out_dir_key = dir_key;
|
||||
*out_dir_entry = dir_entry;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::FindPathRecursive(EntryKey *out_key, RomDirectoryEntry *out_dir_entry, bool is_dir, const RomPathChar *path) {
|
||||
AMS_ASSERT(out_key != nullptr);
|
||||
AMS_ASSERT(out_dir_entry != nullptr);
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
RomPathTool::PathParser parser;
|
||||
R_TRY(parser.Initialize(path));
|
||||
|
||||
EntryKey parent_key = {};
|
||||
Position parent_pos = 0;
|
||||
R_TRY(this->FindParentDirectoryRecursive(std::addressof(parent_pos), std::addressof(parent_key), out_dir_entry, std::addressof(parser), path));
|
||||
|
||||
if (is_dir) {
|
||||
RomPathTool::RomEntryName name = {};
|
||||
R_TRY(parser.GetAsDirectoryName(std::addressof(name)));
|
||||
|
||||
if (RomPathTool::IsCurrentDirectory(name)) {
|
||||
*out_key = parent_key;
|
||||
if (out_key->key.parent != RootPosition) {
|
||||
Position pos = 0;
|
||||
R_TRY(this->GetGrandParent(std::addressof(pos), std::addressof(parent_key), out_dir_entry, out_key->key.parent, out_key->name, path));
|
||||
}
|
||||
} else if (RomPathTool::IsParentDirectory(name)) {
|
||||
R_UNLESS(parent_pos != RootPosition, fs::ResultDirectoryUnobtainable());
|
||||
|
||||
Position pos = 0;
|
||||
RomDirectoryEntry cur_entry = {};
|
||||
R_TRY(this->GetGrandParent(std::addressof(pos), out_key, std::addressof(cur_entry), parent_key.key.parent, parent_key.name, path));
|
||||
|
||||
if (out_key->key.parent != RootPosition) {
|
||||
R_TRY(this->GetGrandParent(std::addressof(pos), std::addressof(parent_key), out_dir_entry, out_key->key.parent, out_key->name, path));
|
||||
}
|
||||
} else {
|
||||
out_key->name = name;
|
||||
out_key->key.parent = (out_key->name.length > 0) ? parent_pos : RootPosition;
|
||||
}
|
||||
} else {
|
||||
{
|
||||
RomPathTool::RomEntryName name = {};
|
||||
R_TRY(parser.GetAsDirectoryName(std::addressof(name)));
|
||||
R_UNLESS(!RomPathTool::IsParentDirectory(name) || parent_pos != RootPosition, fs::ResultDirectoryUnobtainable());
|
||||
}
|
||||
|
||||
R_UNLESS(!parser.IsDirectoryPath(), fs::ResultDbmInvalidOperation());
|
||||
|
||||
out_key->key.parent = parent_pos;
|
||||
R_TRY(parser.GetAsFileName(std::addressof(out_key->name)));
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::FindDirectoryRecursive(EntryKey *out_key, RomDirectoryEntry *out_dir_entry, const RomPathChar *path) {
|
||||
AMS_ASSERT(out_key != nullptr);
|
||||
AMS_ASSERT(out_dir_entry != nullptr);
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
return this->FindPathRecursive(out_key, out_dir_entry, true, path);
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::FindFileRecursive(EntryKey *out_key, RomDirectoryEntry *out_dir_entry, const RomPathChar *path) {
|
||||
AMS_ASSERT(out_key != nullptr);
|
||||
AMS_ASSERT(out_dir_entry != nullptr);
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
return this->FindPathRecursive(out_key, out_dir_entry, false, path);
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::CheckSameEntryExists(const EntryKey &key, Result if_exists) {
|
||||
/* Check dir */
|
||||
{
|
||||
Position pos = InvalidPosition;
|
||||
RomDirectoryEntry entry = {};
|
||||
const Result get_res = this->dir_table.Get(std::addressof(pos), std::addressof(entry), key);
|
||||
if (!fs::ResultDbmKeyNotFound::Includes(get_res)) {
|
||||
R_TRY(get_res);
|
||||
return if_exists;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check file */
|
||||
{
|
||||
Position pos = InvalidPosition;
|
||||
RomFileEntry entry = {};
|
||||
const Result get_res = this->file_table.Get(std::addressof(pos), std::addressof(entry), key);
|
||||
if (!fs::ResultDbmKeyNotFound::Includes(get_res)) {
|
||||
R_TRY(get_res);
|
||||
return if_exists;
|
||||
}
|
||||
}
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::GetDirectoryEntry(Position *out_pos, RomDirectoryEntry *out_entry, const EntryKey &key) {
|
||||
AMS_ASSERT(out_pos != nullptr);
|
||||
AMS_ASSERT(out_entry != nullptr);
|
||||
|
||||
const Result dir_res = this->dir_table.Get(out_pos, out_entry, key);
|
||||
R_UNLESS(R_FAILED(dir_res), dir_res);
|
||||
R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(dir_res), dir_res);
|
||||
|
||||
Position pos = 0;
|
||||
RomFileEntry entry = {};
|
||||
const Result file_res = this->file_table.Get(std::addressof(pos), std::addressof(entry), key);
|
||||
R_UNLESS(R_FAILED(file_res), fs::ResultDbmInvalidOperation());
|
||||
R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(file_res), fs::ResultDbmDirectoryNotFound());
|
||||
return file_res;
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::GetDirectoryEntry(RomDirectoryEntry *out_entry, RomDirectoryId id) {
|
||||
AMS_ASSERT(out_entry != nullptr);
|
||||
Position pos = ConvertToPosition(id);
|
||||
|
||||
RomEntryKey key = {};
|
||||
const Result dir_res = this->dir_table.GetByPosition(std::addressof(key), out_entry, pos);
|
||||
R_UNLESS(R_FAILED(dir_res), dir_res);
|
||||
R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(dir_res), dir_res);
|
||||
|
||||
RomFileEntry entry = {};
|
||||
const Result file_res = this->file_table.GetByPosition(std::addressof(key), std::addressof(entry), pos);
|
||||
R_UNLESS(R_FAILED(file_res), fs::ResultDbmInvalidOperation());
|
||||
R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(file_res), fs::ResultDbmDirectoryNotFound());
|
||||
return file_res;
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::GetFileEntry(Position *out_pos, RomFileEntry *out_entry, const EntryKey &key) {
|
||||
AMS_ASSERT(out_pos != nullptr);
|
||||
AMS_ASSERT(out_entry != nullptr);
|
||||
|
||||
const Result file_res = this->file_table.Get(out_pos, out_entry, key);
|
||||
R_UNLESS(R_FAILED(file_res), file_res);
|
||||
R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(file_res), file_res);
|
||||
|
||||
Position pos = 0;
|
||||
RomDirectoryEntry entry = {};
|
||||
const Result dir_res = this->dir_table.Get(std::addressof(pos), std::addressof(entry), key);
|
||||
R_UNLESS(R_FAILED(dir_res), fs::ResultDbmInvalidOperation());
|
||||
R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(dir_res), fs::ResultDbmFileNotFound());
|
||||
return dir_res;
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::GetFileEntry(RomFileEntry *out_entry, RomFileId id) {
|
||||
AMS_ASSERT(out_entry != nullptr);
|
||||
Position pos = ConvertToPosition(id);
|
||||
|
||||
RomEntryKey key = {};
|
||||
const Result file_res = this->file_table.GetByPosition(std::addressof(key), out_entry, pos);
|
||||
R_UNLESS(R_FAILED(file_res), file_res);
|
||||
R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(file_res), file_res);
|
||||
|
||||
RomDirectoryEntry entry = {};
|
||||
const Result dir_res = this->dir_table.GetByPosition(std::addressof(key), std::addressof(entry), pos);
|
||||
R_UNLESS(R_FAILED(dir_res), fs::ResultDbmInvalidOperation());
|
||||
R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(dir_res), fs::ResultDbmFileNotFound());
|
||||
return dir_res;
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::GetDirectoryInformation(DirectoryInfo *out, const EntryKey &key) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
|
||||
Position pos = 0;
|
||||
RomDirectoryEntry entry = {};
|
||||
R_TRY(this->GetDirectoryEntry(std::addressof(pos), std::addressof(entry), key));
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::OpenFile(FileInfo *out, const EntryKey &key) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
|
||||
Position pos = 0;
|
||||
RomFileEntry entry = {};
|
||||
R_TRY(this->GetFileEntry(std::addressof(pos), std::addressof(entry), key));
|
||||
|
||||
*out = entry.info;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::FindOpen(FindPosition *out, const EntryKey &key) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
|
||||
out->next_dir = InvalidPosition;
|
||||
out->next_file = InvalidPosition;
|
||||
|
||||
Position pos = 0;
|
||||
RomDirectoryEntry entry = {};
|
||||
R_TRY(this->GetDirectoryEntry(std::addressof(pos), std::addressof(entry), key));
|
||||
|
||||
out->next_dir = entry.dir;
|
||||
out->next_file = entry.file;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
|
@ -18,7 +18,7 @@
|
|||
namespace ams::fs::RomPathTool {
|
||||
|
||||
Result PathParser::Initialize(const RomPathChar *path) {
|
||||
AMS_ABORT_UNLESS(path != nullptr);
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
/* Require paths start with a separator, and skip repeated separators. */
|
||||
R_UNLESS(IsSeparator(path[0]), fs::ResultDbmInvalidPathFormat());
|
||||
|
@ -65,10 +65,10 @@ namespace ams::fs::RomPathTool {
|
|||
}
|
||||
|
||||
Result PathParser::GetAsDirectoryName(RomEntryName *out) const {
|
||||
AMS_ABORT_UNLESS(out != nullptr);
|
||||
AMS_ABORT_UNLESS(this->prev_path_start != nullptr);
|
||||
AMS_ABORT_UNLESS(this->prev_path_end != nullptr);
|
||||
AMS_ABORT_UNLESS(this->next_path != nullptr);
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(this->prev_path_start != nullptr);
|
||||
AMS_ASSERT(this->prev_path_end != nullptr);
|
||||
AMS_ASSERT(this->next_path != nullptr);
|
||||
|
||||
const size_t len = this->prev_path_end - this->prev_path_start;
|
||||
R_UNLESS(len <= MaxPathLength, fs::ResultDbmDirectoryNameTooLong());
|
||||
|
@ -79,10 +79,10 @@ namespace ams::fs::RomPathTool {
|
|||
}
|
||||
|
||||
Result PathParser::GetAsFileName(RomEntryName *out) const {
|
||||
AMS_ABORT_UNLESS(out != nullptr);
|
||||
AMS_ABORT_UNLESS(this->prev_path_start != nullptr);
|
||||
AMS_ABORT_UNLESS(this->prev_path_end != nullptr);
|
||||
AMS_ABORT_UNLESS(this->next_path != nullptr);
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(this->prev_path_start != nullptr);
|
||||
AMS_ASSERT(this->prev_path_end != nullptr);
|
||||
AMS_ASSERT(this->next_path != nullptr);
|
||||
|
||||
const size_t len = this->prev_path_end - this->prev_path_start;
|
||||
R_UNLESS(len <= MaxPathLength, fs::ResultDbmFileNameTooLong());
|
||||
|
@ -93,10 +93,10 @@ namespace ams::fs::RomPathTool {
|
|||
}
|
||||
|
||||
Result PathParser::GetNextDirectoryName(RomEntryName *out) {
|
||||
AMS_ABORT_UNLESS(out != nullptr);
|
||||
AMS_ABORT_UNLESS(this->prev_path_start != nullptr);
|
||||
AMS_ABORT_UNLESS(this->prev_path_end != nullptr);
|
||||
AMS_ABORT_UNLESS(this->next_path != nullptr);
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(this->prev_path_start != nullptr);
|
||||
AMS_ASSERT(this->prev_path_end != nullptr);
|
||||
AMS_ASSERT(this->next_path != nullptr);
|
||||
|
||||
/* Set the current path to output. */
|
||||
out->length = this->prev_path_end - this->prev_path_start;
|
||||
|
@ -132,8 +132,8 @@ namespace ams::fs::RomPathTool {
|
|||
}
|
||||
|
||||
Result GetParentDirectoryName(RomEntryName *out, const RomEntryName &cur, const RomPathChar *p) {
|
||||
AMS_ABORT_UNLESS(out != nullptr);
|
||||
AMS_ABORT_UNLESS(p != nullptr);
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(p != nullptr);
|
||||
|
||||
const RomPathChar *start = cur.path;
|
||||
const RomPathChar *end = cur.path + cur.length - 1;
|
||||
|
@ -158,6 +158,7 @@ namespace ams::fs::RomPathTool {
|
|||
|
||||
if (depth == 0) {
|
||||
start = head + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
while (IsSeparator(*head)) {
|
540
libraries/libstratosphere/source/fs/fs_romfs_filesystem.cpp
Normal file
540
libraries/libstratosphere/source/fs/fs_romfs_filesystem.cpp
Normal file
|
@ -0,0 +1,540 @@
|
|||
/*
|
||||
* 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::fs {
|
||||
|
||||
namespace {
|
||||
|
||||
Result ConvertNcaCorruptedResult(Result res) {
|
||||
AMS_ASSERT(fs::ResultNcaCorrupted::Includes(res));
|
||||
|
||||
R_TRY_CATCH(res) {
|
||||
R_CONVERT(fs::ResultInvalidNcaFileSystemType, fs::ResultInvalidRomNcaFileSystemType())
|
||||
R_CONVERT(fs::ResultInvalidAcidFileSize, fs::ResultInvalidRomAcidFileSize())
|
||||
R_CONVERT(fs::ResultInvalidAcidSize, fs::ResultInvalidRomAcidSize())
|
||||
R_CONVERT(fs::ResultInvalidAcid, fs::ResultInvalidRomAcid())
|
||||
R_CONVERT(fs::ResultAcidVerificationFailed, fs::ResultRomAcidVerificationFailed())
|
||||
R_CONVERT(fs::ResultInvalidNcaSignature, fs::ResultInvalidRomNcaSignature())
|
||||
R_CONVERT(fs::ResultNcaHeaderSignature1VerificationFailed, fs::ResultRomNcaHeaderSignature1VerificationFailed())
|
||||
R_CONVERT(fs::ResultNcaHeaderSignature2VerificationFailed, fs::ResultRomNcaHeaderSignature2VerificationFailed())
|
||||
R_CONVERT(fs::ResultNcaFsHeaderHashVerificationFailed, fs::ResultRomNcaFsHeaderHashVerificationFailed())
|
||||
R_CONVERT(fs::ResultInvalidNcaKeyIndex, fs::ResultInvalidRomNcaKeyIndex())
|
||||
R_CONVERT(fs::ResultInvalidNcaFsHeaderHashType, fs::ResultInvalidRomNcaFsHeaderHashType())
|
||||
R_CONVERT(fs::ResultInvalidNcaFsHeaderEncryptionType, fs::ResultInvalidRomNcaFsHeaderEncryptionType())
|
||||
R_CONVERT(fs::ResultInvalidHierarchicalSha256BlockSize, fs::ResultInvalidRomHierarchicalSha256BlockSize())
|
||||
R_CONVERT(fs::ResultInvalidHierarchicalSha256LayerCount, fs::ResultInvalidRomHierarchicalSha256LayerCount())
|
||||
R_CONVERT(fs::ResultHierarchicalSha256BaseStorageTooLarge, fs::ResultRomHierarchicalSha256BaseStorageTooLarge())
|
||||
R_CONVERT(fs::ResultHierarchicalSha256HashVerificationFailed, fs::ResultRomHierarchicalSha256HashVerificationFailed())
|
||||
R_CATCH_ALL() { /* ... */ }
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
AMS_ASSERT(false);
|
||||
return fs::ResultNcaCorrupted();
|
||||
}
|
||||
|
||||
Result ConvertIntegrityVerificationStorageCorruptedResult(Result res) {
|
||||
AMS_ASSERT(fs::ResultIntegrityVerificationStorageCorrupted::Includes(res));
|
||||
|
||||
R_TRY_CATCH(res) {
|
||||
R_CONVERT(fs::ResultIncorrectIntegrityVerificationMagic, fs::ResultIncorrectRomIntegrityVerificationMagic())
|
||||
R_CONVERT(fs::ResultInvalidZeroHash, fs::ResultInvalidRomZeroHash())
|
||||
R_CONVERT(fs::ResultNonRealDataVerificationFailed, fs::ResultRomNonRealDataVerificationFailed())
|
||||
R_CONVERT(fs::ResultInvalidHierarchicalIntegrityVerificationLayerCount, fs::ResultInvalidRomHierarchicalIntegrityVerificationLayerCount())
|
||||
R_CONVERT(fs::ResultClearedRealDataVerificationFailed, fs::ResultClearedRomRealDataVerificationFailed())
|
||||
R_CONVERT(fs::ResultUnclearedRealDataVerificationFailed, fs::ResultUnclearedRomRealDataVerificationFailed())
|
||||
R_CATCH_ALL() { /* ... */ }
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
AMS_ASSERT(false);
|
||||
return fs::ResultIntegrityVerificationStorageCorrupted();
|
||||
}
|
||||
|
||||
Result ConvertBuiltInStorageCorruptedResult(Result res) {
|
||||
AMS_ASSERT(fs::ResultBuiltInStorageCorrupted::Includes(res));
|
||||
|
||||
R_TRY_CATCH(res) {
|
||||
R_CONVERT(fs::ResultGptHeaderVerificationFailed, fs::ResultRomGptHeaderVerificationFailed())
|
||||
R_CATCH_ALL() { /* ... */ }
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
AMS_ASSERT(false);
|
||||
return fs::ResultBuiltInStorageCorrupted();
|
||||
}
|
||||
|
||||
Result ConvertPartitionFileSystemCorruptedResult(Result res) {
|
||||
AMS_ASSERT(fs::ResultPartitionFileSystemCorrupted::Includes(res));
|
||||
|
||||
R_TRY_CATCH(res) {
|
||||
R_CONVERT(fs::ResultInvalidSha256PartitionHashTarget, fs::ResultInvalidRomSha256PartitionHashTarget())
|
||||
R_CONVERT(fs::ResultSha256PartitionHashVerificationFailed, fs::ResultRomSha256PartitionHashVerificationFailed())
|
||||
R_CONVERT(fs::ResultPartitionSignatureVerificationFailed, fs::ResultRomPartitionSignatureVerificationFailed())
|
||||
R_CONVERT(fs::ResultSha256PartitionSignatureVerificationFailed, fs::ResultRomSha256PartitionSignatureVerificationFailed())
|
||||
R_CONVERT(fs::ResultInvalidPartitionEntryOffset, fs::ResultInvalidRomPartitionEntryOffset())
|
||||
R_CONVERT(fs::ResultInvalidSha256PartitionMetaDataSize, fs::ResultInvalidRomSha256PartitionMetaDataSize())
|
||||
R_CATCH_ALL() { /* ... */ }
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
AMS_ASSERT(false);
|
||||
return fs::ResultPartitionFileSystemCorrupted();
|
||||
}
|
||||
|
||||
Result ConvertFatFileSystemCorruptedResult(Result res) {
|
||||
AMS_ASSERT(fs::ResultFatFileSystemCorrupted::Includes(res));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Result ConvertHostFileSystemCorruptedResult(Result res) {
|
||||
AMS_ASSERT(fs::ResultHostFileSystemCorrupted::Includes(res));
|
||||
|
||||
R_TRY_CATCH(res) {
|
||||
R_CONVERT(fs::ResultHostEntryCorrupted, fs::ResultRomHostEntryCorrupted())
|
||||
R_CONVERT(fs::ResultHostFileDataCorrupted, fs::ResultRomHostFileDataCorrupted())
|
||||
R_CONVERT(fs::ResultHostFileCorrupted, fs::ResultRomHostFileCorrupted())
|
||||
R_CONVERT(fs::ResultInvalidHostHandle, fs::ResultInvalidRomHostHandle())
|
||||
R_CATCH_ALL() { /* ... */ }
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
AMS_ASSERT(false);
|
||||
return fs::ResultHostFileSystemCorrupted();
|
||||
}
|
||||
|
||||
Result ConvertDatabaseCorruptedResult(Result res) {
|
||||
AMS_ASSERT(fs::ResultDatabaseCorrupted::Includes(res));
|
||||
|
||||
R_TRY_CATCH(res) {
|
||||
R_CONVERT(fs::ResultInvalidAllocationTableBlock, fs::ResultInvalidRomAllocationTableBlock())
|
||||
R_CONVERT(fs::ResultInvalidKeyValueListElementIndex, fs::ResultInvalidRomKeyValueListElementIndex())
|
||||
R_CATCH_ALL() { /* ... */ }
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
AMS_ASSERT(false);
|
||||
return fs::ResultDatabaseCorrupted();
|
||||
}
|
||||
|
||||
Result ConvertRomFsResult(Result res) {
|
||||
R_TRY_CATCH(res) {
|
||||
R_CONVERT(fs::ResultUnsupportedVersion, fs::ResultUnsupportedRomVersion())
|
||||
R_CONVERT(fs::ResultNcaCorrupted, ConvertNcaCorruptedResult(res))
|
||||
R_CONVERT(fs::ResultIntegrityVerificationStorageCorrupted, ConvertIntegrityVerificationStorageCorruptedResult(res))
|
||||
R_CONVERT(fs::ResultBuiltInStorageCorrupted, ConvertBuiltInStorageCorruptedResult(res))
|
||||
R_CONVERT(fs::ResultPartitionFileSystemCorrupted, ConvertPartitionFileSystemCorruptedResult(res))
|
||||
R_CONVERT(fs::ResultFatFileSystemCorrupted, ConvertFatFileSystemCorruptedResult(res))
|
||||
R_CONVERT(fs::ResultHostFileSystemCorrupted, ConvertHostFileSystemCorruptedResult(res))
|
||||
R_CONVERT(fs::ResultDatabaseCorrupted, ConvertDatabaseCorruptedResult(res))
|
||||
R_CONVERT(fs::ResultNotFound, fs::ResultPathNotFound())
|
||||
R_CONVERT(fs::ResultPermissionDenied, fs::ResultTargetLocked())
|
||||
R_CONVERT(fs::ResultIncompatiblePath, fs::ResultPathNotFound())
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ReadFile(IStorage *storage, s64 offset, void *buffer, size_t size) {
|
||||
AMS_ASSERT(storage != nullptr);
|
||||
AMS_ASSERT(offset >= 0);
|
||||
AMS_ASSERT(buffer != nullptr || size == 0);
|
||||
|
||||
return ConvertRomFsResult(storage->Read(offset, buffer, size));
|
||||
}
|
||||
|
||||
Result ReadFileHeader(IStorage *storage, RomFileSystemInformation *out) {
|
||||
AMS_ASSERT(storage != nullptr);
|
||||
AMS_ASSERT(out != nullptr);
|
||||
|
||||
return ReadFile(storage, 0, out, sizeof(*out));
|
||||
}
|
||||
|
||||
constexpr size_t CalculateRequiredWorkingMemorySize(const RomFileSystemInformation &header) {
|
||||
const size_t needed_size = header.directory_bucket_size + header.directory_entry_size + header.file_bucket_size + header.file_entry_size;
|
||||
return util::AlignUp(needed_size, 8);
|
||||
}
|
||||
|
||||
class RomFsFile : public fsa::IFile, public impl::Newable {
|
||||
private:
|
||||
RomFsFileSystem *parent;
|
||||
s64 start;
|
||||
s64 end;
|
||||
public:
|
||||
RomFsFile(RomFsFileSystem *p, s64 s, s64 e) : parent(p), start(s), end(e) { /* ... */ }
|
||||
virtual ~RomFsFile() { /* ... */ }
|
||||
|
||||
Result VerifyArguments(size_t *out, s64 offset, void *buf, size_t size, const fs::ReadOption &option) {
|
||||
R_TRY(DryRead(out, offset, size, option, fs::OpenMode_Read));
|
||||
|
||||
AMS_ASSERT(this->GetStorage() != nullptr);
|
||||
AMS_ASSERT(offset >= 0);
|
||||
AMS_ASSERT(buf != nullptr || size == 0);
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ConvertResult(Result res) const {
|
||||
return ConvertRomFsResult(res);
|
||||
}
|
||||
|
||||
s64 GetOffset() const {
|
||||
return this->start;
|
||||
}
|
||||
|
||||
s64 GetSize() const {
|
||||
return this->end - this->start;
|
||||
}
|
||||
|
||||
IStorage *GetStorage() {
|
||||
return this->parent->GetBaseStorage();
|
||||
}
|
||||
public:
|
||||
virtual Result ReadImpl(size_t *out, s64 offset, void *buffer, size_t size, const fs::ReadOption &option) override {
|
||||
size_t read_size = 0;
|
||||
R_TRY(this->VerifyArguments(std::addressof(read_size), offset, buffer, size, option));
|
||||
|
||||
R_TRY(this->ConvertResult(this->GetStorage()->Read(offset + this->start, buffer, size)));
|
||||
*out = read_size;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
virtual Result GetSizeImpl(s64 *out) override {
|
||||
*out = this->GetSize();
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
virtual Result FlushImpl() override {
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
virtual Result WriteImpl(s64 offset, const void *buffer, size_t size, const fs::WriteOption &option) override {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result SetSizeImpl(s64 size) override {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
virtual Result OperateRangeImpl(void *dst, size_t dst_size, fs::OperationId op_id, s64 offset, s64 size, const void *src, size_t src_size) override {
|
||||
switch (op_id) {
|
||||
case OperationId::InvalidateCache:
|
||||
case OperationId::QueryRange:
|
||||
{
|
||||
R_UNLESS(offset >= 0, fs::ResultOutOfRange());
|
||||
R_UNLESS(this->GetSize() >= 0, fs::ResultOutOfRange());
|
||||
}
|
||||
default:
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
}
|
||||
public:
|
||||
virtual sf::cmif::DomainObjectId GetDomainObjectId() const override {
|
||||
AMS_ABORT();
|
||||
}
|
||||
};
|
||||
|
||||
class RomFsDirectory : public fsa::IDirectory, public impl::Newable {
|
||||
private:
|
||||
using FindPosition = RomFsFileSystem::RomFileTable::FindPosition;
|
||||
private:
|
||||
RomFsFileSystem *parent;
|
||||
FindPosition current_find;
|
||||
FindPosition first_find;
|
||||
fs::OpenDirectoryMode mode;
|
||||
public:
|
||||
RomFsDirectory(RomFsFileSystem *p, const FindPosition &f, fs::OpenDirectoryMode m) : parent(p), current_find(f), first_find(f), mode(m) { /* ... */ }
|
||||
virtual ~RomFsDirectory() override { /* ... */ }
|
||||
public:
|
||||
virtual Result ReadImpl(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) {
|
||||
return this->ReadImpl(out_count, std::addressof(this->current_find), out_entries, max_entries);
|
||||
}
|
||||
|
||||
virtual Result GetEntryCountImpl(s64 *out) {
|
||||
FindPosition find = this->first_find;
|
||||
return this->ReadImpl(out, std::addressof(find), nullptr, 0);
|
||||
}
|
||||
private:
|
||||
Result ReadImpl(s64 *out_count, FindPosition *find, DirectoryEntry *out_entries, s64 max_entries) {
|
||||
AMS_ASSERT(out_count != nullptr);
|
||||
AMS_ASSERT(find != nullptr);
|
||||
|
||||
constexpr size_t NameBufferSize = fs::EntryNameLengthMax + 1;
|
||||
char *name_buf = static_cast<char *>(::ams::fs::impl::Allocate(NameBufferSize));
|
||||
R_UNLESS(name_buf != nullptr, fs::ResultAllocationFailureInRomFsFileSystemE());
|
||||
ON_SCOPE_EXIT { ::ams::fs::impl::Deallocate(name_buf, NameBufferSize); };
|
||||
|
||||
s32 i = 0;
|
||||
|
||||
if (this->mode & fs::OpenDirectoryMode_Directory) {
|
||||
while (i < max_entries || out_entries == nullptr) {
|
||||
R_TRY_CATCH(this->parent->GetRomFileTable()->FindNextDirectory(name_buf, find, NameBufferSize)) {
|
||||
R_CATCH(fs::ResultDbmFindFinished) { break; }
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
if (out_entries) {
|
||||
R_UNLESS(strnlen(name_buf, NameBufferSize) < NameBufferSize, fs::ResultTooLongPath());
|
||||
strncpy(out_entries[i].name, name_buf, fs::EntryNameLengthMax);
|
||||
out_entries[i].name[fs::EntryNameLengthMax] = '\x00';
|
||||
out_entries[i].type = fs::DirectoryEntryType_Directory;
|
||||
out_entries[i].file_size = 0;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->mode & fs::OpenDirectoryMode_File) {
|
||||
while (i < max_entries || out_entries == nullptr) {
|
||||
auto file_pos = find->next_file;
|
||||
|
||||
R_TRY_CATCH(this->parent->GetRomFileTable()->FindNextFile(name_buf, find, NameBufferSize)) {
|
||||
R_CATCH(fs::ResultDbmFindFinished) { break; }
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
if (out_entries) {
|
||||
R_UNLESS(strnlen(name_buf, NameBufferSize) < NameBufferSize, fs::ResultTooLongPath());
|
||||
strncpy(out_entries[i].name, name_buf, fs::EntryNameLengthMax);
|
||||
out_entries[i].name[fs::EntryNameLengthMax] = '\x00';
|
||||
out_entries[i].type = fs::DirectoryEntryType_File;
|
||||
|
||||
RomFsFileSystem::RomFileTable::FileInfo file_info;
|
||||
R_TRY(this->parent->GetRomFileTable()->OpenFile(std::addressof(file_info), this->parent->GetRomFileTable()->ConvertToFileId(file_pos)));
|
||||
out_entries[i].file_size = file_info.size.Get();
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
*out_count = i;
|
||||
return ResultSuccess();
|
||||
}
|
||||
public:
|
||||
virtual sf::cmif::DomainObjectId GetDomainObjectId() const override {
|
||||
AMS_ABORT();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
RomFsFileSystem::RomFsFileSystem() : base_storage() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
RomFsFileSystem::~RomFsFileSystem() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
Result RomFsFileSystem::GetRequiredWorkingMemorySize(size_t *out, IStorage *storage) {
|
||||
RomFileSystemInformation header;
|
||||
R_TRY(ReadFileHeader(storage, std::addressof(header)));
|
||||
|
||||
*out = CalculateRequiredWorkingMemorySize(header);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result RomFsFileSystem:: Initialize(IStorage *base, void *work, size_t work_size, bool use_cache) {
|
||||
AMS_ABORT_UNLESS(!use_cache || work != nullptr);
|
||||
AMS_ABORT_UNLESS(base != nullptr);
|
||||
|
||||
/* Read the header. */
|
||||
RomFileSystemInformation header;
|
||||
R_TRY(ReadFileHeader(base, std::addressof(header)));
|
||||
|
||||
/* Set up our storages. */
|
||||
if (use_cache) {
|
||||
const size_t needed_size = CalculateRequiredWorkingMemorySize(header);
|
||||
R_UNLESS(work_size >= needed_size, fs::ResultPreconditionViolation());
|
||||
|
||||
u8 *buf = static_cast<u8 *>(work);
|
||||
auto dir_bucket_buf = buf; buf += header.directory_bucket_size;
|
||||
auto dir_entry_buf = buf; buf += header.directory_entry_size;
|
||||
auto file_bucket_buf = buf; buf += header.file_bucket_size;
|
||||
auto file_entry_buf = buf; buf += header.file_entry_size;
|
||||
|
||||
R_TRY(ReadFile(base, header.directory_bucket_offset, dir_bucket_buf, header.directory_bucket_size));
|
||||
R_TRY(ReadFile(base, header.directory_entry_offset, dir_entry_buf, header.directory_entry_size));
|
||||
R_TRY(ReadFile(base, header.file_bucket_offset, file_bucket_buf, header.file_bucket_size));
|
||||
R_TRY(ReadFile(base, header.file_entry_offset, file_entry_buf, header.file_entry_size));
|
||||
|
||||
this->dir_bucket_storage.reset(new MemoryStorage(dir_bucket_buf, header.directory_bucket_size));
|
||||
this->dir_entry_storage.reset(new MemoryStorage(dir_entry_buf, header.directory_entry_size));
|
||||
this->file_bucket_storage.reset(new MemoryStorage(file_bucket_buf, header.file_bucket_size));
|
||||
this->file_entry_storage.reset(new MemoryStorage(file_entry_buf, header.file_entry_size));
|
||||
} else {
|
||||
this->dir_bucket_storage.reset(new SubStorage(base, header.directory_bucket_offset, header.directory_bucket_size));
|
||||
this->dir_entry_storage.reset(new SubStorage(base, header.directory_entry_offset, header.directory_entry_size));
|
||||
this->file_bucket_storage.reset(new SubStorage(base, header.file_bucket_offset, header.file_bucket_size));
|
||||
this->file_entry_storage.reset(new SubStorage(base, header.file_entry_offset, header.file_entry_size));
|
||||
}
|
||||
|
||||
/* Ensure we allocated storages successfully. */
|
||||
R_UNLESS(this->dir_bucket_storage != nullptr, fs::ResultAllocationFailureInRomFsFileSystemA());
|
||||
R_UNLESS(this->dir_entry_storage != nullptr, fs::ResultAllocationFailureInRomFsFileSystemA());
|
||||
R_UNLESS(this->file_bucket_storage != nullptr, fs::ResultAllocationFailureInRomFsFileSystemA());
|
||||
R_UNLESS(this->file_entry_storage != nullptr, fs::ResultAllocationFailureInRomFsFileSystemA());
|
||||
|
||||
/* Initialize the rom table. */
|
||||
{
|
||||
|
||||
SubStorage db(this->dir_bucket_storage.get(), 0, header.directory_bucket_size);
|
||||
SubStorage de(this->dir_entry_storage.get(), 0, header.directory_entry_size);
|
||||
SubStorage fb(this->file_bucket_storage.get(), 0, header.file_bucket_size);
|
||||
SubStorage fe(this->file_entry_storage.get(), 0, header.file_entry_size);
|
||||
R_TRY(this->rom_file_table.Initialize(db, de, fb, fe));
|
||||
}
|
||||
|
||||
/* Set members. */
|
||||
this->entry_size = header.body_offset;
|
||||
this->base_storage = base;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result RomFsFileSystem::Initialize(std::unique_ptr<IStorage>&& base, void *work, size_t work_size, bool use_cache) {
|
||||
this->unique_storage = std::move(base);
|
||||
return this->Initialize(this->unique_storage.get(), work, work_size, use_cache);
|
||||
}
|
||||
|
||||
Result RomFsFileSystem::GetFileInfo(RomFileTable::FileInfo *out, const char *path) {
|
||||
R_TRY_CATCH(this->rom_file_table.OpenFile(out, path)) {
|
||||
R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound());
|
||||
R_CONVERT(fs::ResultDbmInvalidOperation, fs::ResultPathNotFound());
|
||||
} R_END_TRY_CATCH;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
IStorage *RomFsFileSystem::GetBaseStorage() {
|
||||
return this->base_storage;
|
||||
}
|
||||
|
||||
RomFsFileSystem::RomFileTable *RomFsFileSystem::GetRomFileTable() {
|
||||
return std::addressof(this->rom_file_table);
|
||||
}
|
||||
|
||||
Result RomFsFileSystem::GetFileBaseOffset(s64 *out, const char *path) {
|
||||
AMS_ABORT_UNLESS(out != nullptr);
|
||||
AMS_ABORT_UNLESS(path != nullptr);
|
||||
|
||||
RomFileTable::FileInfo info;
|
||||
R_TRY(this->GetFileInfo(std::addressof(info), path));
|
||||
*out = this->entry_size + info.offset.Get();
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result RomFsFileSystem::CreateFileImpl(const char *path, s64 size, int flags) {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
Result RomFsFileSystem::DeleteFileImpl(const char *path) {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
Result RomFsFileSystem::CreateDirectoryImpl(const char *path) {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
Result RomFsFileSystem::DeleteDirectoryImpl(const char *path) {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
Result RomFsFileSystem::DeleteDirectoryRecursivelyImpl(const char *path) {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
Result RomFsFileSystem::RenameFileImpl(const char *old_path, const char *new_path) {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
Result RomFsFileSystem::RenameDirectoryImpl(const char *old_path, const char *new_path) {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
Result RomFsFileSystem::GetEntryTypeImpl(fs::DirectoryEntryType *out, const char *path) {
|
||||
RomDirectoryInfo dir_info;
|
||||
R_TRY_CATCH(this->rom_file_table.GetDirectoryInformation(std::addressof(dir_info), path)) {
|
||||
R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound())
|
||||
R_CATCH(fs::ResultDbmInvalidOperation) {
|
||||
RomFileTable::FileInfo file_info;
|
||||
R_TRY(this->GetFileInfo(std::addressof(file_info), path));
|
||||
*out = fs::DirectoryEntryType_File;
|
||||
return ResultSuccess();
|
||||
}
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
*out = fs::DirectoryEntryType_Directory;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result RomFsFileSystem::OpenFileImpl(std::unique_ptr<fs::fsa::IFile> *out_file, const char *path, fs::OpenMode mode) {
|
||||
AMS_ASSERT(out_file != nullptr);
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
R_UNLESS((mode & fs::OpenMode_All) == fs::OpenMode_Read, fs::ResultInvalidArgument());
|
||||
|
||||
RomFileTable::FileInfo file_info;
|
||||
R_TRY(this->GetFileInfo(std::addressof(file_info), path));
|
||||
|
||||
std::unique_ptr<RomFsFile> file(new RomFsFile(this, this->entry_size + file_info.offset.Get(), this->entry_size + file_info.offset.Get() + file_info.size.Get()));
|
||||
R_UNLESS(file != nullptr, fs::ResultAllocationFailureInRomFsFileSystemB());
|
||||
|
||||
*out_file = std::move(file);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result RomFsFileSystem::OpenDirectoryImpl(std::unique_ptr<fs::fsa::IDirectory> *out_dir, const char *path, fs::OpenDirectoryMode mode) {
|
||||
AMS_ASSERT(out_dir != nullptr);
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
RomFileTable::FindPosition find;
|
||||
R_TRY_CATCH(this->rom_file_table.FindOpen(std::addressof(find), path)) {
|
||||
R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound())
|
||||
R_CONVERT(fs::ResultDbmInvalidOperation, fs::ResultPathNotFound())
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
std::unique_ptr<RomFsDirectory> dir(new RomFsDirectory(this, find, mode));
|
||||
R_UNLESS(dir != nullptr, fs::ResultAllocationFailureInRomFsFileSystemC());
|
||||
|
||||
*out_dir = std::move(dir);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result RomFsFileSystem::CommitImpl() {
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result RomFsFileSystem::GetFreeSpaceSizeImpl(s64 *out, const char *path) {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
Result RomFsFileSystem::GetTotalSpaceSizeImpl(s64 *out, const char *path) {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
Result RomFsFileSystem::CleanDirectoryRecursivelyImpl(const char *path) {
|
||||
return fs::ResultUnsupportedOperation();
|
||||
}
|
||||
|
||||
Result RomFsFileSystem::CommitProvisionallyImpl(s64 counter) {
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result RomFsFileSystem::RollbackImpl() {
|
||||
return ResultSuccess();
|
||||
}
|
||||
}
|
33
libraries/libstratosphere/source/fs/fs_system_data.cpp
Normal file
33
libraries/libstratosphere/source/fs/fs_system_data.cpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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>
|
||||
#include "fsa/fs_mount_utils.hpp"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
Result QueryMountSystemDataCacheSize(size_t *out, ncm::ProgramId data_id) {
|
||||
return impl::QueryMountDataCacheSize(out, data_id, ncm::StorageId::BuiltInSystem);
|
||||
}
|
||||
|
||||
Result MountSystemData(const char *name, ncm::ProgramId data_id) {
|
||||
return impl::MountData(name, data_id, ncm::StorageId::BuiltInSystem);
|
||||
}
|
||||
|
||||
Result MountSystemData(const char *name, ncm::ProgramId data_id, void *cache_buffer, size_t cache_size) {
|
||||
return impl::MountData(name, data_id, ncm::StorageId::BuiltInSystem, cache_buffer, cache_size);
|
||||
}
|
||||
|
||||
}
|
|
@ -44,8 +44,9 @@ namespace ams::fs {
|
|||
|
||||
R_DEFINE_ERROR_RANGE(GameCardAccessFailed, 2500, 2999);
|
||||
|
||||
R_DEFINE_ERROR_RESULT(NotImplemented, 3001);
|
||||
R_DEFINE_ERROR_RESULT(OutOfRange, 3005);
|
||||
R_DEFINE_ERROR_RESULT(NotImplemented, 3001);
|
||||
R_DEFINE_ERROR_RESULT(UnsupportedVersion, 3002);
|
||||
R_DEFINE_ERROR_RESULT(OutOfRange, 3005);
|
||||
|
||||
R_DEFINE_ERROR_RESULT(SystemPartitionNotReady, 3100);
|
||||
|
||||
|
@ -54,6 +55,8 @@ namespace ams::fs {
|
|||
R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemAccessorB, 3212);
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailureInContentStorageA, 3220);
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailureInContentStorageB, 3221);
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailureInDataA, 3222);
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailureInDataB, 3223);
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailureInGameCardA, 3225);
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailureInGameCardB, 3226);
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailureInGameCardC, 3227);
|
||||
|
@ -61,11 +64,17 @@ namespace ams::fs {
|
|||
R_DEFINE_ERROR_RESULT(AllocationFailureInSdCardA, 3244);
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailureInSdCardB, 3245);
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailureInSystemSaveDataA, 3246);
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemA, 3247);
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemB, 3248);
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemC, 3249);
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailureInDirectorySaveDataFileSystem, 3321);
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemD, 3352);
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailureInSubDirectoryFileSystem, 3355);
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailureInRegisterA, 3365);
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailureInRegisterB, 3366);
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailureInPathNormalizer, 3367);
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailureInDbmRomKeyValueStorage, 3375);
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemE, 3377);
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemInterfaceAdapter, 3407);
|
||||
R_DEFINE_ERROR_RESULT(AllocationFailureInUserFileSystem, 3420);
|
||||
|
||||
|
@ -73,13 +82,115 @@ namespace ams::fs {
|
|||
|
||||
R_DEFINE_ERROR_RANGE(DataCorrupted, 4000, 4999);
|
||||
R_DEFINE_ERROR_RANGE(RomCorrupted, 4001, 4299);
|
||||
R_DEFINE_ERROR_RESULT(UnsupportedRomVersion, 4002);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(RomNcaCorrupted, 4041, 4139);
|
||||
R_DEFINE_ERROR_RANGE(RomNcaFileSystemCorrupted, 4051, 4069);
|
||||
R_DEFINE_ERROR_RESULT(InvalidRomNcaFileSystemType, 4052);
|
||||
R_DEFINE_ERROR_RESULT(InvalidRomAcidFileSize, 4053);
|
||||
R_DEFINE_ERROR_RESULT(InvalidRomAcidSize, 4054);
|
||||
R_DEFINE_ERROR_RESULT(InvalidRomAcid, 4055);
|
||||
R_DEFINE_ERROR_RESULT(RomAcidVerificationFailed, 4056);
|
||||
R_DEFINE_ERROR_RESULT(InvalidRomNcaSignature, 4057);
|
||||
R_DEFINE_ERROR_RESULT(RomNcaHeaderSignature1VerificationFailed, 4058);
|
||||
R_DEFINE_ERROR_RESULT(RomNcaHeaderSignature2VerificationFailed, 4059);
|
||||
R_DEFINE_ERROR_RESULT(RomNcaFsHeaderHashVerificationFailed, 4060);
|
||||
R_DEFINE_ERROR_RESULT(InvalidRomNcaKeyIndex, 4061);
|
||||
R_DEFINE_ERROR_RESULT(InvalidRomNcaFsHeaderHashType, 4062);
|
||||
R_DEFINE_ERROR_RESULT(InvalidRomNcaFsHeaderEncryptionType, 4063);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(RomNcaHierarchicalSha256StorageCorrupted, 4071, 4079);
|
||||
R_DEFINE_ERROR_RESULT(InvalidRomHierarchicalSha256BlockSize, 4072);
|
||||
R_DEFINE_ERROR_RESULT(InvalidRomHierarchicalSha256LayerCount, 4073);
|
||||
R_DEFINE_ERROR_RESULT(RomHierarchicalSha256BaseStorageTooLarge, 4074);
|
||||
R_DEFINE_ERROR_RESULT(RomHierarchicalSha256HashVerificationFailed, 4075);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(RomIntegrityVerificationStorageCorrupted, 4141, 4179);
|
||||
R_DEFINE_ERROR_RESULT(IncorrectRomIntegrityVerificationMagic, 4142);
|
||||
R_DEFINE_ERROR_RESULT(InvalidRomZeroHash, 4143);
|
||||
R_DEFINE_ERROR_RESULT(RomNonRealDataVerificationFailed, 4144);
|
||||
R_DEFINE_ERROR_RESULT(InvalidRomHierarchicalIntegrityVerificationLayerCount, 4145);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(RomRealDataVerificationFailed, 4151, 4159);
|
||||
R_DEFINE_ERROR_RESULT(ClearedRomRealDataVerificationFailed, 4152);
|
||||
R_DEFINE_ERROR_RESULT(UnclearedRomRealDataVerificationFailed, 4153);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(RomPartitionFileSystemCorrupted, 4181, 4199);
|
||||
R_DEFINE_ERROR_RESULT(InvalidRomSha256PartitionHashTarget, 4182);
|
||||
R_DEFINE_ERROR_RESULT(RomSha256PartitionHashVerificationFailed, 4183);
|
||||
R_DEFINE_ERROR_RESULT(RomPartitionSignatureVerificationFailed, 4184);
|
||||
R_DEFINE_ERROR_RESULT(RomSha256PartitionSignatureVerificationFailed, 4185);
|
||||
R_DEFINE_ERROR_RESULT(InvalidRomPartitionEntryOffset, 4186);
|
||||
R_DEFINE_ERROR_RESULT(InvalidRomSha256PartitionMetaDataSize, 4187);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(RomBuiltInStorageCorrupted, 4201, 4219);
|
||||
R_DEFINE_ERROR_RESULT(RomGptHeaderVerificationFailed, 4202);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(RomHostFileSystemCorrupted, 4241, 4259);
|
||||
R_DEFINE_ERROR_RESULT(RomHostEntryCorrupted, 4242);
|
||||
R_DEFINE_ERROR_RESULT(RomHostFileDataCorrupted, 4243);
|
||||
R_DEFINE_ERROR_RESULT(RomHostFileCorrupted, 4244);
|
||||
R_DEFINE_ERROR_RESULT(InvalidRomHostHandle, 4245);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(RomDatabaseCorrupted, 4261, 4279);
|
||||
R_DEFINE_ERROR_RESULT(InvalidRomAllocationTableBlock, 4262);
|
||||
R_DEFINE_ERROR_RESULT(InvalidRomKeyValueListElementIndex, 4263);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(SaveDataCorrupted, 4301, 4499);
|
||||
R_DEFINE_ERROR_RANGE(NcaCorrupted, 4501, 4599);
|
||||
R_DEFINE_ERROR_RANGE(NcaFileSystemCorrupted, 4511, 4529);
|
||||
R_DEFINE_ERROR_RESULT(InvalidNcaFileSystemType, 4512);
|
||||
R_DEFINE_ERROR_RESULT(InvalidAcidFileSize, 4513);
|
||||
R_DEFINE_ERROR_RESULT(InvalidAcidSize, 4514);
|
||||
R_DEFINE_ERROR_RESULT(InvalidAcid, 4515);
|
||||
R_DEFINE_ERROR_RESULT(AcidVerificationFailed, 4516);
|
||||
R_DEFINE_ERROR_RESULT(InvalidNcaSignature, 4517);
|
||||
R_DEFINE_ERROR_RESULT(NcaHeaderSignature1VerificationFailed, 4518);
|
||||
R_DEFINE_ERROR_RESULT(NcaHeaderSignature2VerificationFailed, 4519);
|
||||
R_DEFINE_ERROR_RESULT(NcaFsHeaderHashVerificationFailed, 4520);
|
||||
R_DEFINE_ERROR_RESULT(InvalidNcaKeyIndex, 4521);
|
||||
R_DEFINE_ERROR_RESULT(InvalidNcaFsHeaderHashType, 4522);
|
||||
R_DEFINE_ERROR_RESULT(InvalidNcaFsHeaderEncryptionType, 4523);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(NcaHierarchicalSha256StorageCorrupted, 4531, 4539);
|
||||
R_DEFINE_ERROR_RESULT(InvalidHierarchicalSha256BlockSize, 4532);
|
||||
R_DEFINE_ERROR_RESULT(InvalidHierarchicalSha256LayerCount, 4533);
|
||||
R_DEFINE_ERROR_RESULT(HierarchicalSha256BaseStorageTooLarge, 4534);
|
||||
R_DEFINE_ERROR_RESULT(HierarchicalSha256HashVerificationFailed, 4535);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(IntegrityVerificationStorageCorrupted, 4601, 4639);
|
||||
R_DEFINE_ERROR_RESULT(IncorrectIntegrityVerificationMagic, 4602);
|
||||
R_DEFINE_ERROR_RESULT(InvalidZeroHash, 4603);
|
||||
R_DEFINE_ERROR_RESULT(NonRealDataVerificationFailed, 4604);
|
||||
R_DEFINE_ERROR_RESULT(InvalidHierarchicalIntegrityVerificationLayerCount, 4605);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(RealDataVerificationFailed, 4611, 4619);
|
||||
R_DEFINE_ERROR_RESULT(ClearedRealDataVerificationFailed, 4612);
|
||||
R_DEFINE_ERROR_RESULT(UnclearedRealDataVerificationFailed, 4613);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(PartitionFileSystemCorrupted, 4641, 4659);
|
||||
R_DEFINE_ERROR_RESULT(InvalidSha256PartitionHashTarget, 4642);
|
||||
R_DEFINE_ERROR_RESULT(Sha256PartitionHashVerificationFailed, 4643);
|
||||
R_DEFINE_ERROR_RESULT(PartitionSignatureVerificationFailed, 4644);
|
||||
R_DEFINE_ERROR_RESULT(Sha256PartitionSignatureVerificationFailed, 4645);
|
||||
R_DEFINE_ERROR_RESULT(InvalidPartitionEntryOffset, 4646);
|
||||
R_DEFINE_ERROR_RESULT(InvalidSha256PartitionMetaDataSize, 4647);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(BuiltInStorageCorrupted, 4661, 4679);
|
||||
R_DEFINE_ERROR_RESULT(GptHeaderVerificationFailed, 4662);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(FatFileSystemCorrupted, 4681, 4699);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(HostFileSystemCorrupted, 4701, 4719);
|
||||
R_DEFINE_ERROR_RESULT(HostEntryCorrupted, 4702);
|
||||
R_DEFINE_ERROR_RESULT(HostFileDataCorrupted, 4703);
|
||||
R_DEFINE_ERROR_RESULT(HostFileCorrupted, 4704);
|
||||
R_DEFINE_ERROR_RESULT(InvalidHostHandle, 4705);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(DatabaseCorrupted, 4721, 4739);
|
||||
R_DEFINE_ERROR_RESULT(InvalidAllocationTableBlock, 4722);
|
||||
R_DEFINE_ERROR_RESULT(InvalidKeyValueListElementIndex, 4723);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(AesXtsFileSystemCorrupted, 4741, 4759);
|
||||
R_DEFINE_ERROR_RANGE(SaveDataTransferDataCorrupted, 4761, 4769);
|
||||
R_DEFINE_ERROR_RANGE(SignedSystemPartitionDataCorrupted, 4771, 4779);
|
||||
|
@ -132,6 +243,8 @@ namespace ams::fs {
|
|||
R_DEFINE_ERROR_RESULT(AllocatorAlignmentViolation, 6461);
|
||||
R_DEFINE_ERROR_RESULT(UserNotExist, 6465);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(NotFound, 6600, 6699);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(OutOfResource, 6700, 6799);
|
||||
R_DEFINE_ERROR_RESULT(MappingTableFull, 6706);
|
||||
R_DEFINE_ERROR_RESULT(OpenCountLimit, 6709);
|
||||
|
@ -143,9 +256,24 @@ namespace ams::fs {
|
|||
R_DEFINE_ERROR_RESULT(NotInitialized, 6902);
|
||||
R_DEFINE_ERROR_RESULT(NotMounted, 6905);
|
||||
|
||||
R_DEFINE_ERROR_RESULT(DbmInvalidOperation, 7914);
|
||||
R_DEFINE_ERROR_RESULT(DbmInvalidPathFormat, 7915);
|
||||
R_DEFINE_ERROR_RESULT(DbmDirectoryNameTooLong, 7916);
|
||||
R_DEFINE_ERROR_RESULT(DbmFileNameTooLong, 7917);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(DbmNotFound, 7901, 7904);
|
||||
R_DEFINE_ERROR_RESULT(DbmKeyNotFound, 7902);
|
||||
R_DEFINE_ERROR_RESULT(DbmFileNotFound, 7903);
|
||||
R_DEFINE_ERROR_RESULT(DbmDirectoryNotFound, 7904);
|
||||
|
||||
R_DEFINE_ERROR_RESULT(DbmAlreadyExists, 7906);
|
||||
R_DEFINE_ERROR_RESULT(DbmKeyFull, 7907);
|
||||
R_DEFINE_ERROR_RESULT(DbmDirectoryEntryFull, 7908);
|
||||
R_DEFINE_ERROR_RESULT(DbmFileEntryFull, 7909);
|
||||
|
||||
R_DEFINE_ERROR_RANGE(DbmFindFinished, 7910, 7912);
|
||||
R_DEFINE_ERROR_RESULT(DbmFindKeyFinished, 7911);
|
||||
R_DEFINE_ERROR_RESULT(DbmIterationFinished, 7912);
|
||||
|
||||
R_DEFINE_ERROR_RESULT(DbmInvalidOperation, 7914);
|
||||
R_DEFINE_ERROR_RESULT(DbmInvalidPathFormat, 7915);
|
||||
R_DEFINE_ERROR_RESULT(DbmDirectoryNameTooLong, 7916);
|
||||
R_DEFINE_ERROR_RESULT(DbmFileNameTooLong, 7917);
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue