mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-09 22:56:35 +00:00
fs/system: deduplicate RomFs code
This commit is contained in:
parent
c45088d1cd
commit
73167448cc
16 changed files with 226 additions and 1723 deletions
|
@ -14,9 +14,9 @@
|
|||
* 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"
|
||||
#include <stratosphere/fs/common/fs_dbm_rom_types.hpp>
|
||||
#include <stratosphere/fs/common/fs_dbm_rom_path_tool.hpp>
|
||||
#include <stratosphere/fs/common/fs_dbm_rom_key_value_storage.hpp>
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
|
@ -33,19 +33,23 @@ namespace ams::fs {
|
|||
using DirectoryInfo = RomDirectoryInfo;
|
||||
using FileInfo = RomFileInfo;
|
||||
|
||||
static constexpr RomFileId ConvertToFileId(Position pos) {
|
||||
static constexpr RomFileId PositionToFileId(Position pos) {
|
||||
return static_cast<RomFileId>(pos);
|
||||
}
|
||||
|
||||
static constexpr Position FileIdToPosition(RomFileId id) {
|
||||
return static_cast<Position>(id);
|
||||
}
|
||||
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) {
|
||||
static constexpr RomDirectoryId PositionToDirectoryId(Position pos) {
|
||||
return static_cast<RomDirectoryId>(pos);
|
||||
}
|
||||
|
||||
static constexpr Position ConvertToPosition(RomDirectoryId id) {
|
||||
static constexpr Position DirectoryIdToPosition(RomDirectoryId id) {
|
||||
return static_cast<Position>(id);
|
||||
}
|
||||
|
||||
|
@ -67,20 +71,20 @@ namespace ams::fs {
|
|||
static constexpr inline u32 MaxKeyLength = RomPathTool::MaxPathLength;
|
||||
|
||||
template<typename ImplKeyType, typename ClientKeyType, typename ValueType>
|
||||
class EntryMapTable : public RomKeyValueStorage<ImplKeyType, ValueType, MaxKeyLength> {
|
||||
class EntryMapTable : public KeyValueRomStorageTemplate<ImplKeyType, ValueType, MaxKeyLength> {
|
||||
public:
|
||||
using ImplKey = ImplKeyType;
|
||||
using ClientKey = ClientKeyType;
|
||||
using Value = ValueType;
|
||||
using Position = HierarchicalRomFileTable::Position;
|
||||
using Base = RomKeyValueStorage<ImplKeyType, ValueType, MaxKeyLength>;
|
||||
using Base = KeyValueRomStorageTemplate<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);
|
||||
return Base::AddInternal(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));
|
||||
return Base::GetInternal(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) {
|
||||
|
@ -118,7 +122,7 @@ namespace ams::fs {
|
|||
constexpr u32 Hash() const {
|
||||
u32 hash = this->key.parent ^ 123456789;
|
||||
const RomPathChar * name = this->name.path;
|
||||
const RomPathChar *end = name + this->name.length;
|
||||
const RomPathChar * const 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;
|
||||
|
@ -134,10 +138,10 @@ namespace ams::fs {
|
|||
DirectoryEntryMapTable dir_table;
|
||||
FileEntryMapTable file_table;
|
||||
public:
|
||||
static s64 QueryDirectoryEntryStorageSize(u32 count);
|
||||
static s64 QueryDirectoryEntryBucketStorageSize(s64 count);
|
||||
static s64 QueryFileEntryStorageSize(u32 count);
|
||||
static size_t QueryDirectoryEntrySize(size_t aux_size);
|
||||
static s64 QueryFileEntryBucketStorageSize(s64 count);
|
||||
static size_t QueryFileEntrySize(size_t aux_size);
|
||||
|
||||
static Result Format(SubStorage dir_bucket, SubStorage file_bucket);
|
||||
public:
|
|
@ -14,13 +14,13 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "fs_dbm_rom_types.hpp"
|
||||
#include "fs_substorage.hpp"
|
||||
#include <stratosphere/fs/common/fs_dbm_rom_types.hpp>
|
||||
#include <stratosphere/fs/fs_substorage.hpp>
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
template<typename KeyType, typename ValueType, size_t MaxAuxiliarySize>
|
||||
class RomKeyValueStorage {
|
||||
class KeyValueRomStorageTemplate {
|
||||
public:
|
||||
using Key = KeyType;
|
||||
using Value = ValueType;
|
||||
|
@ -57,8 +57,8 @@ namespace ams::fs {
|
|||
return size / sizeof(Position);
|
||||
}
|
||||
|
||||
static constexpr s64 QueryKeyValueStorageSize(u32 num) {
|
||||
return num * sizeof(Element);
|
||||
static constexpr size_t QueryEntrySize(size_t aux_size) {
|
||||
return util::AlignUp(sizeof(Element) + aux_size, alignof(Element));
|
||||
}
|
||||
|
||||
static Result Format(SubStorage bucket, s64 count) {
|
||||
|
@ -69,13 +69,13 @@ namespace ams::fs {
|
|||
return ResultSuccess();
|
||||
}
|
||||
public:
|
||||
RomKeyValueStorage() : bucket_count(), bucket_storage(), kv_storage(), total_entry_size(), entry_count() { /* ... */ }
|
||||
KeyValueRomStorageTemplate() : 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;
|
||||
this->kv_storage = kv;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
|
@ -100,82 +100,17 @@ namespace ams::fs {
|
|||
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);
|
||||
}
|
||||
|
||||
void FindOpen(FindIndex *out) const {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
|
||||
out->ind = static_cast<BucketIndex>(-1);
|
||||
out->pos = InvalidPosition;
|
||||
}
|
||||
|
||||
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) {
|
||||
Result AddInternal(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(aux != nullptr || aux_size == 0);
|
||||
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);
|
||||
const Result find_res = this->FindInternal(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);
|
||||
}
|
||||
|
@ -195,14 +130,14 @@ namespace ams::fs {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetImpl(Position *out_pos, Value *out_val, const Key &key, u32 hash_key, const void *aux, size_t aux_size) {
|
||||
Result GetInternal(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));
|
||||
R_TRY(this->FindInternal(std::addressof(pos), std::addressof(prev_pos), std::addressof(elem), key, hash_key, aux, aux_size));
|
||||
|
||||
*out_pos = pos;
|
||||
*out_val = elem.value;
|
||||
|
@ -246,11 +181,11 @@ namespace ams::fs {
|
|||
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) {
|
||||
Result FindInternal(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(aux != nullptr || aux_size == 0);
|
||||
AMS_ASSERT(this->bucket_count > 0);
|
||||
|
||||
*out_pos = 0;
|
||||
|
@ -296,7 +231,7 @@ namespace ams::fs {
|
|||
|
||||
*out = static_cast<Position>(this->total_entry_size);
|
||||
|
||||
this->total_entry_size = util::AlignUp(static_cast<s64>(end_pos), s64(4));
|
||||
this->total_entry_size = util::AlignUp(static_cast<s64>(end_pos), alignof(Position));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere/fs/common/fs_dbm_rom_types.hpp>
|
||||
|
||||
namespace ams::fs::RomPathTool {
|
||||
|
||||
constexpr inline u32 MaxPathLength = 0x300;
|
||||
|
||||
struct RomEntryName {
|
||||
size_t length;
|
||||
const RomPathChar *path;
|
||||
};
|
||||
static_assert(util::is_pod<RomEntryName>::value);
|
||||
|
||||
constexpr void InitEntryName(RomEntryName *entry) {
|
||||
AMS_ASSERT(entry != nullptr);
|
||||
entry->length = 0;
|
||||
}
|
||||
|
||||
constexpr inline bool IsSeparator(RomPathChar c) {
|
||||
return c == RomStringTraits::DirectorySeparator;
|
||||
}
|
||||
|
||||
constexpr inline bool IsNullTerminator(RomPathChar c) {
|
||||
return c == RomStringTraits::NullTerminator;
|
||||
}
|
||||
|
||||
constexpr inline bool IsDot(RomPathChar c) {
|
||||
return c == RomStringTraits::Dot;
|
||||
}
|
||||
|
||||
constexpr inline bool IsCurrentDirectory(const RomEntryName &name) {
|
||||
return name.length == 1 && IsDot(name.path[0]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsCurrentDirectory(const RomPathChar *p, size_t length) {
|
||||
AMS_ASSERT(p != nullptr);
|
||||
return length == 1 && IsDot(p[0]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsCurrentDirectory(const RomPathChar *p) {
|
||||
AMS_ASSERT(p != nullptr);
|
||||
return IsDot(p[0]) && IsNullTerminator(p[1]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsParentDirectory(const RomEntryName &name) {
|
||||
return name.length == 2 && IsDot(name.path[0]) && IsDot(name.path[1]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsParentDirectory(const RomPathChar *p) {
|
||||
AMS_ASSERT(p != nullptr);
|
||||
return IsDot(p[0]) && IsDot(p[1]) && IsNullTerminator(p[2]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsParentDirectory(const RomPathChar *p, size_t length) {
|
||||
AMS_ASSERT(p != nullptr);
|
||||
return length == 2 && IsDot(p[0]) && IsDot(p[1]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsEqualPath(const RomPathChar *lhs, const RomPathChar *rhs, size_t length) {
|
||||
AMS_ASSERT(lhs != nullptr);
|
||||
AMS_ASSERT(rhs != nullptr);
|
||||
return std::strncmp(lhs, rhs, length) == 0;
|
||||
}
|
||||
|
||||
Result GetParentDirectoryName(RomEntryName *out, const RomEntryName &cur, const RomPathChar *p);
|
||||
|
||||
class PathParser {
|
||||
private:
|
||||
const RomPathChar *prev_path_start;
|
||||
const RomPathChar *prev_path_end;
|
||||
const RomPathChar *next_path;
|
||||
bool finished;
|
||||
public:
|
||||
constexpr PathParser() : prev_path_start(), prev_path_end(), next_path(), finished() { /* ... */ }
|
||||
|
||||
Result Initialize(const RomPathChar *path);
|
||||
void Finalize();
|
||||
|
||||
bool IsParseFinished() const;
|
||||
bool IsDirectoryPath() const;
|
||||
|
||||
Result GetAsDirectoryName(RomEntryName *out) const;
|
||||
Result GetAsFileName(RomEntryName *out) const;
|
||||
|
||||
Result GetNextDirectoryName(RomEntryName *out);
|
||||
};
|
||||
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "fs_common.hpp"
|
||||
#include <stratosphere/fs/fs_common.hpp>
|
||||
|
||||
namespace ams::fs {
|
||||
|
|
@ -1,122 +0,0 @@
|
|||
/*
|
||||
* 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"
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
namespace RomPathTool {
|
||||
|
||||
constexpr inline u32 MaxPathLength = 0x300;
|
||||
|
||||
struct RomEntryName {
|
||||
size_t length;
|
||||
const RomPathChar *path;
|
||||
};
|
||||
static_assert(util::is_pod<RomEntryName>::value);
|
||||
|
||||
constexpr void InitializeRomEntryName(RomEntryName *entry) {
|
||||
AMS_ABORT_UNLESS(entry != nullptr);
|
||||
entry->length = 0;
|
||||
}
|
||||
|
||||
constexpr inline bool IsSeparator(RomPathChar c) {
|
||||
return c == RomStringTraits::DirectorySeparator;
|
||||
}
|
||||
|
||||
constexpr inline bool IsNullTerminator(RomPathChar c) {
|
||||
return c == RomStringTraits::NullTerminator;
|
||||
}
|
||||
|
||||
constexpr inline bool IsDot(RomPathChar c) {
|
||||
return c == RomStringTraits::Dot;
|
||||
}
|
||||
|
||||
constexpr inline bool IsCurrentDirectory(const RomEntryName &name) {
|
||||
return name.length == 1 && IsDot(name.path[0]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsCurrentDirectory(const RomPathChar *p, size_t length) {
|
||||
AMS_ABORT_UNLESS(p != nullptr);
|
||||
return length == 1 && IsDot(p[0]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsCurrentDirectory(const RomPathChar *p) {
|
||||
AMS_ABORT_UNLESS(p != nullptr);
|
||||
return IsDot(p[0]) && IsNullTerminator(p[1]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsParentDirectory(const RomEntryName &name) {
|
||||
return name.length == 2 && IsDot(name.path[0]) && IsDot(name.path[1]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsParentDirectory(const RomPathChar *p) {
|
||||
AMS_ABORT_UNLESS(p != nullptr);
|
||||
return IsDot(p[0]) && IsDot(p[1]) && IsNullTerminator(p[2]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsParentDirectory(const RomPathChar *p, size_t length) {
|
||||
AMS_ABORT_UNLESS(p != nullptr);
|
||||
return length == 2 && IsDot(p[0]) && IsDot(p[1]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsEqualPath(const RomPathChar *lhs, const RomPathChar *rhs, size_t length) {
|
||||
AMS_ABORT_UNLESS(lhs != nullptr);
|
||||
AMS_ABORT_UNLESS(rhs != nullptr);
|
||||
return std::strncmp(lhs, rhs, length) == 0;
|
||||
}
|
||||
|
||||
constexpr inline bool IsEqualName(const RomEntryName &lhs, const RomPathChar *rhs) {
|
||||
AMS_ABORT_UNLESS(rhs != nullptr);
|
||||
if (strnlen(rhs, MaxPathLength) != lhs.length) {
|
||||
return false;
|
||||
}
|
||||
return IsEqualPath(lhs.path, rhs, lhs.length);
|
||||
}
|
||||
|
||||
constexpr inline bool IsEqualName(const RomEntryName &lhs, const RomEntryName &rhs) {
|
||||
if (lhs.length != rhs.length) {
|
||||
return false;
|
||||
}
|
||||
return IsEqualPath(lhs.path, rhs.path, lhs.length);
|
||||
}
|
||||
|
||||
Result GetParentDirectoryName(RomEntryName *out, const RomEntryName &cur, const RomPathChar *p);
|
||||
|
||||
class PathParser {
|
||||
private:
|
||||
const RomPathChar *prev_path_start;
|
||||
const RomPathChar *prev_path_end;
|
||||
const RomPathChar *next_path;
|
||||
bool finished;
|
||||
public:
|
||||
constexpr PathParser() : prev_path_start(), prev_path_end(), next_path(), finished() { /* ... */ }
|
||||
|
||||
Result Initialize(const RomPathChar *path);
|
||||
void Finalize();
|
||||
|
||||
bool IsFinished() const;
|
||||
bool IsDirectoryPath() const;
|
||||
|
||||
Result GetAsDirectoryName(RomEntryName *out) const;
|
||||
Result GetAsFileName(RomEntryName *out) const;
|
||||
|
||||
Result GetNextDirectoryName(RomEntryName *out);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -14,12 +14,12 @@
|
|||
* 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"
|
||||
#include <stratosphere/fs/fs_common.hpp>
|
||||
#include <stratosphere/fs/impl/fs_newable.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_ifile.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_idirectory.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_ifilesystem.hpp>
|
||||
#include <stratosphere/fs/common/fs_dbm_hierarchical_rom_file_table.hpp>
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
|
|
|
@ -1,684 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/fssystem/fssystem_dbm_rom_types.hpp>
|
||||
#include <stratosphere/fssystem/fssystem_dbm_rom_path_tool.hpp>
|
||||
#include <stratosphere/fssystem/fssystem_dbm_rom_key_value_storage.hpp>
|
||||
|
||||
namespace ams::fssystem {
|
||||
|
||||
template<typename DBS, typename DES, typename FBS, typename FES>
|
||||
class HierarchicalRomFileTable {
|
||||
private:
|
||||
using DirectoryBucketStorage = DBS;
|
||||
using DirectoryEntryStorage = DES;
|
||||
using FileBucketStorage = FBS;
|
||||
using FileEntryStorage = FES;
|
||||
public:
|
||||
using Position = u32;
|
||||
|
||||
struct FindPosition {
|
||||
Position next_dir;
|
||||
Position next_file;
|
||||
};
|
||||
static_assert(util::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(util::is_pod<RomDirectoryEntry>::value);
|
||||
|
||||
struct RomFileEntry {
|
||||
Position next;
|
||||
FileInfo info;
|
||||
};
|
||||
static_assert(util::is_pod<RomFileEntry>::value);
|
||||
|
||||
static constexpr inline u32 MaxKeyLength = RomPathTool::MaxPathLength;
|
||||
|
||||
template<typename BucketStorageType, typename EntryStorageType, typename ImplKeyType, typename ClientKeyType, typename ValueType>
|
||||
class EntryMapTable : public RomKeyValueStorage<BucketStorageType, EntryStorageType, ImplKeyType, ValueType, MaxKeyLength> {
|
||||
private:
|
||||
using BucketStorage = BucketStorageType;
|
||||
using EntryStorage = EntryStorageType;
|
||||
public:
|
||||
using ImplKey = ImplKeyType;
|
||||
using ClientKey = ClientKeyType;
|
||||
using Value = ValueType;
|
||||
using Position = HierarchicalRomFileTable::Position;
|
||||
using Base = RomKeyValueStorage<BucketStorageType, EntryStorageType, 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) const {
|
||||
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, void *out_aux, size_t *out_aux_size, Position pos) const {
|
||||
return Base::GetByPosition(out_key, out_val, out_aux, out_aux_size, pos);
|
||||
}
|
||||
|
||||
Result SetByPosition(Position pos, const Value &value, fs::WriteOption option) const {
|
||||
return Base::SetByPosition(pos, value, option);
|
||||
}
|
||||
};
|
||||
|
||||
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(util::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(util::is_pod<EntryKey>::value);
|
||||
|
||||
using DirectoryEntryMapTable = EntryMapTable<DirectoryBucketStorage, DirectoryEntryStorage, RomEntryKey, EntryKey, RomDirectoryEntry>;
|
||||
using FileEntryMapTable = EntryMapTable<FileBucketStorage, FileEntryStorage, RomEntryKey, EntryKey, RomFileEntry>;
|
||||
private:
|
||||
DirectoryEntryMapTable dir_table;
|
||||
FileEntryMapTable file_table;
|
||||
public:
|
||||
static u32 QueryDirectoryEntrySize(u32 name_len) {
|
||||
AMS_ABORT_UNLESS(name_len <= RomPathTool::MaxPathLength);
|
||||
return DirectoryEntryMapTable::QueryEntrySize(name_len * sizeof(RomPathChar));
|
||||
}
|
||||
|
||||
static u32 QueryFileEntrySize(u32 name_len) {
|
||||
AMS_ABORT_UNLESS(name_len <= RomPathTool::MaxPathLength);
|
||||
return FileEntryMapTable::QueryEntrySize(name_len * sizeof(RomPathChar));
|
||||
}
|
||||
|
||||
static u32 QueryDirectoryEntryBucketStorageSize(u32 count) { return DirectoryEntryMapTable::QueryBucketStorageSize(count); }
|
||||
static u32 QueryFileEntryBucketStorageSize(u32 count) { return FileEntryMapTable::QueryBucketStorageSize(count); }
|
||||
|
||||
static Result Format(DirectoryBucketStorage *dir_bucket, s64 dir_bucket_ofs, u32 dir_bucket_size, DirectoryEntryStorage *dir_entry, s64 dir_entry_ofs, u32 dir_entry_size, FileBucketStorage *file_bucket, s64 file_bucket_ofs, u32 file_bucket_size, FileEntryStorage *file_entry, s64 file_entry_ofs, u32 file_entry_size) {
|
||||
R_TRY(DirectoryEntryMapTable::Format(dir_bucket, dir_bucket_ofs, DirectoryEntryMapTable::QueryBucketCount(dir_bucket_size), dir_entry, dir_entry_ofs, dir_entry_size));
|
||||
R_TRY(FileEntryMapTable::Format(file_bucket, file_bucket_ofs, FileEntryMapTable::QueryBucketCount(file_bucket_size), file_entry, file_entry_ofs, file_entry_size));
|
||||
return ResultSuccess();
|
||||
}
|
||||
public:
|
||||
HierarchicalRomFileTable() { /* ... */ }
|
||||
|
||||
constexpr u32 GetDirectoryEntryCount() const {
|
||||
return this->dir_table.GetEntryCount();
|
||||
}
|
||||
|
||||
constexpr u32 GetFileEntryCount() const {
|
||||
return this->file_table.GetEntryCount();
|
||||
}
|
||||
|
||||
Result Initialize(DirectoryBucketStorage *dir_bucket, s64 dir_bucket_ofs, u32 dir_bucket_size, DirectoryEntryStorage *dir_entry, s64 dir_entry_ofs, u32 dir_entry_size, FileBucketStorage *file_bucket, s64 file_bucket_ofs, u32 file_bucket_size, FileEntryStorage *file_entry, s64 file_entry_ofs, u32 file_entry_size) {
|
||||
AMS_ASSERT(dir_bucket != nullptr);
|
||||
AMS_ASSERT(dir_entry != nullptr);
|
||||
AMS_ASSERT(file_bucket != nullptr);
|
||||
AMS_ASSERT(file_entry != nullptr);
|
||||
|
||||
R_TRY(this->dir_table.Initialize(dir_bucket, dir_bucket_ofs, DirectoryEntryMapTable::QueryBucketCount(dir_bucket_size), dir_entry, dir_entry_ofs, dir_entry_size));
|
||||
R_TRY(this->file_table.Initialize(file_bucket, file_bucket_ofs, FileEntryMapTable::QueryBucketCount(file_bucket_size), file_entry, file_entry_ofs, file_entry_size));
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void Finalize() {
|
||||
this->dir_table.Finalize();
|
||||
this->file_table.Finalize();
|
||||
}
|
||||
|
||||
Result 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 CreateDirectory(RomDirectoryId *out, const RomPathChar *path, const DirectoryInfo &info) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
EntryKey parent_key = {};
|
||||
RomDirectoryEntry parent_entry = {};
|
||||
EntryKey new_key = {};
|
||||
R_TRY(this->FindDirectoryRecursive(std::addressof(parent_key), std::addressof(parent_entry), std::addressof(new_key), 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, fs::WriteOption::None));
|
||||
} 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), nullptr, nullptr, cur_pos));
|
||||
|
||||
if (cur_entry.next == InvalidPosition) {
|
||||
cur_entry.next = new_pos;
|
||||
|
||||
R_TRY(this->dir_table.SetByPosition(cur_pos, cur_entry, fs::WriteOption::None));
|
||||
break;
|
||||
}
|
||||
|
||||
cur_pos = cur_entry.next;
|
||||
}
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result CreateFile(RomFileId *out, const RomPathChar *path, const FileInfo &info) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
EntryKey parent_key = {};
|
||||
RomDirectoryEntry parent_entry = {};
|
||||
EntryKey new_key = {};
|
||||
R_TRY(this->FindFileRecursive(std::addressof(parent_key), std::addressof(parent_entry), std::addressof(new_key), 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, fs::WriteOption::None));
|
||||
} 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), nullptr, nullptr, cur_pos));
|
||||
|
||||
if (cur_entry.next == InvalidPosition) {
|
||||
cur_entry.next = new_pos;
|
||||
|
||||
R_TRY(this->file_table.SetByPosition(cur_pos, cur_entry, fs::WriteOption::None));
|
||||
break;
|
||||
}
|
||||
|
||||
cur_pos = cur_entry.next;
|
||||
}
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ConvertPathToDirectoryId(RomDirectoryId *out, const RomPathChar *path) const {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
EntryKey parent_key = {};
|
||||
RomDirectoryEntry parent_entry = {};
|
||||
EntryKey key = {};
|
||||
R_TRY(this->FindDirectoryRecursive(std::addressof(parent_key), std::addressof(parent_entry), std::addressof(key), path));
|
||||
|
||||
Position pos = 0;
|
||||
RomDirectoryEntry entry = {};
|
||||
R_TRY(this->GetDirectoryEntry(std::addressof(pos), std::addressof(entry), key));
|
||||
|
||||
*out = ConvertToDirectoryId(pos);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ConvertPathToFileId(RomFileId *out, const RomPathChar *path) const {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
EntryKey parent_key = {};
|
||||
RomDirectoryEntry parent_entry = {};
|
||||
EntryKey key = {};
|
||||
R_TRY(this->FindDirectoryRecursive(std::addressof(parent_key), std::addressof(parent_entry), std::addressof(key), path));
|
||||
|
||||
Position pos = 0;
|
||||
RomFileEntry entry = {};
|
||||
R_TRY(this->GetFileEntry(std::addressof(pos), std::addressof(entry), key));
|
||||
|
||||
*out = ConvertToFileId(pos);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetDirectoryInformation(DirectoryInfo *out, const RomPathChar *path) const {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
EntryKey parent_key = {};
|
||||
RomDirectoryEntry parent_entry = {};
|
||||
EntryKey key = {};
|
||||
R_TRY(this->FindDirectoryRecursive(std::addressof(parent_key), std::addressof(parent_entry), std::addressof(key), path));
|
||||
|
||||
return this->GetDirectoryInformation(out, key);
|
||||
}
|
||||
|
||||
Result GetDirectoryInformation(DirectoryInfo *out, RomDirectoryId id) const {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
|
||||
RomDirectoryEntry entry = {};
|
||||
R_TRY(this->GetDirectoryEntry(std::addressof(entry), id));
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result OpenFile(FileInfo *out, const RomPathChar *path) const {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
EntryKey parent_key = {};
|
||||
RomDirectoryEntry parent_entry = {};
|
||||
EntryKey key = {};
|
||||
R_TRY(this->FindFileRecursive(std::addressof(parent_key), std::addressof(parent_entry), std::addressof(key), path));
|
||||
|
||||
return this->OpenFile(out, key);
|
||||
}
|
||||
|
||||
Result OpenFile(FileInfo *out, RomFileId id) const {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
|
||||
RomFileEntry entry = {};
|
||||
R_TRY(this->GetFileEntry(std::addressof(entry), id));
|
||||
|
||||
*out = entry.info;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result FindOpen(FindPosition *out, const RomPathChar *path) const {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
EntryKey parent_key = {};
|
||||
RomDirectoryEntry parent_entry = {};
|
||||
EntryKey key = {};
|
||||
R_TRY(this->FindDirectoryRecursive(std::addressof(parent_key), std::addressof(parent_entry), std::addressof(key), path));
|
||||
|
||||
return this->FindOpen(out, key);
|
||||
}
|
||||
|
||||
Result FindOpen(FindPosition *out, RomDirectoryId id) const {
|
||||
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 FindNextDirectory(RomPathChar *out, FindPosition *find) const {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(find != nullptr);
|
||||
|
||||
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));
|
||||
|
||||
out[aux_size / sizeof(RomPathChar)] = RomStringTraits::NullTerminator;
|
||||
|
||||
find->next_dir = entry.next;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result FindNextFile(RomPathChar *out, FindPosition *find) const {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(find != nullptr);
|
||||
|
||||
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));
|
||||
|
||||
out[aux_size / sizeof(RomPathChar)] = RomStringTraits::NullTerminator;
|
||||
|
||||
find->next_file = entry.next;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result QueryRomFileSystemSize(u32 *out_dir_entry_size, u32 *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();
|
||||
}
|
||||
private:
|
||||
Result GetGrandParent(Position *out_pos, EntryKey *out_dir_key, RomDirectoryEntry *out_dir_entry, Position pos, RomPathTool::RomEntryName name, const RomPathChar *path) const {
|
||||
AMS_ASSERT(out_pos != nullptr);
|
||||
AMS_ASSERT(out_dir_key != nullptr);
|
||||
AMS_ASSERT(out_dir_entry != nullptr);
|
||||
|
||||
RomEntryKey gp_key = {};
|
||||
RomDirectoryEntry gp_entry = {};
|
||||
R_TRY(this->dir_table.GetByPosition(std::addressof(gp_key), std::addressof(gp_entry), nullptr, nullptr, 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 FindParentDirectoryRecursive(Position *out_pos, EntryKey *out_dir_key, RomDirectoryEntry *out_dir_entry, RomPathTool::PathParser &parser, const RomPathChar *path) const {
|
||||
AMS_ASSERT(out_pos != nullptr);
|
||||
AMS_ASSERT(out_dir_key != nullptr);
|
||||
AMS_ASSERT(out_dir_entry != 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::ResultDbmInvalidOperation());
|
||||
|
||||
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(this->GetDirectoryEntry(std::addressof(dir_pos), std::addressof(dir_entry), dir_key));
|
||||
|
||||
parent_pos = dir_pos;
|
||||
}
|
||||
}
|
||||
|
||||
*out_pos = parent_pos;
|
||||
*out_dir_key = dir_key;
|
||||
*out_dir_entry = dir_entry;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result FindPathRecursive(EntryKey *out_parent_key, RomDirectoryEntry *out_parent_dir_entry, EntryKey *out_key, bool is_dir, const RomPathChar *path) const {
|
||||
AMS_ASSERT(out_parent_key != nullptr);
|
||||
AMS_ASSERT(out_parent_dir_entry != nullptr);
|
||||
AMS_ASSERT(out_key != nullptr);
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
RomPathTool::PathParser parser;
|
||||
R_TRY(parser.Initialize(path));
|
||||
|
||||
Position parent_pos = 0;
|
||||
R_TRY(this->FindParentDirectoryRecursive(std::addressof(parent_pos), out_parent_key, out_parent_dir_entry, parser, path));
|
||||
|
||||
if (is_dir) {
|
||||
RomPathTool::RomEntryName name = {};
|
||||
R_TRY(parser.GetAsDirectoryName(std::addressof(name)));
|
||||
|
||||
if (RomPathTool::IsCurrentDirectory(name)) {
|
||||
*out_key = *out_parent_key;
|
||||
if (out_key->key.parent != RootPosition) {
|
||||
Position pos = 0;
|
||||
R_TRY(this->GetGrandParent(std::addressof(pos), out_parent_key, out_parent_dir_entry, out_key->key.parent, out_key->name, path));
|
||||
}
|
||||
} else if (RomPathTool::IsParentDirectory(name)) {
|
||||
R_UNLESS(parent_pos != RootPosition, fs::ResultDbmInvalidOperation());
|
||||
|
||||
Position pos = 0;
|
||||
RomDirectoryEntry cur_entry = {};
|
||||
R_TRY(this->GetGrandParent(std::addressof(pos), out_key, std::addressof(cur_entry), out_parent_key->key.parent, out_parent_key->name, path));
|
||||
|
||||
if (out_key->key.parent != RootPosition) {
|
||||
R_TRY(this->GetGrandParent(std::addressof(pos), out_parent_key, out_parent_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 {
|
||||
R_UNLESS(!parser.IsDirectoryPath(), fs::ResultDbmInvalidOperation());
|
||||
|
||||
out_key->key.parent = parent_pos;
|
||||
R_TRY(parser.GetAsFileName(std::addressof(out_key->name)));
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result FindDirectoryRecursive(EntryKey *out_parent_key, RomDirectoryEntry *out_parent_dir_entry, EntryKey *out_key, const RomPathChar *path) const {
|
||||
return this->FindPathRecursive(out_parent_key, out_parent_dir_entry, out_key, true, path);
|
||||
}
|
||||
|
||||
Result FindFileRecursive(EntryKey *out_parent_key, RomDirectoryEntry *out_parent_dir_entry, EntryKey *out_key, const RomPathChar *path) const {
|
||||
return this->FindPathRecursive(out_parent_key, out_parent_dir_entry, out_key, false, path);
|
||||
}
|
||||
|
||||
Result CheckSameEntryExists(const EntryKey &key, Result if_exists) const {
|
||||
/* 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 GetDirectoryEntry(Position *out_pos, RomDirectoryEntry *out_entry, const EntryKey &key) const {
|
||||
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 GetDirectoryEntry(RomDirectoryEntry *out_entry, RomDirectoryId id) const {
|
||||
AMS_ASSERT(out_entry != nullptr);
|
||||
Position pos = ConvertToPosition(id);
|
||||
|
||||
RomEntryKey key = {};
|
||||
const Result dir_res = this->dir_table.GetByPosition(std::addressof(key), out_entry, nullptr, nullptr, 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), nullptr, nullptr, pos);
|
||||
R_UNLESS(R_FAILED(file_res), fs::ResultDbmInvalidOperation());
|
||||
R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(file_res), fs::ResultDbmDirectoryNotFound());
|
||||
return file_res;
|
||||
}
|
||||
|
||||
Result GetFileEntry(Position *out_pos, RomFileEntry *out_entry, const EntryKey &key) const {
|
||||
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 GetFileEntry(RomFileEntry *out_entry, RomFileId id) const {
|
||||
AMS_ASSERT(out_entry != nullptr);
|
||||
Position pos = ConvertToPosition(id);
|
||||
|
||||
RomEntryKey key = {};
|
||||
const Result file_res = this->file_table.GetByPosition(std::addressof(key), out_entry, nullptr, nullptr, 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), nullptr, nullptr, pos);
|
||||
R_UNLESS(R_FAILED(dir_res), fs::ResultDbmInvalidOperation());
|
||||
R_UNLESS(!fs::ResultDbmKeyNotFound::Includes(dir_res), fs::ResultDbmFileNotFound());
|
||||
return dir_res;
|
||||
}
|
||||
|
||||
Result GetDirectoryInformation(DirectoryInfo *out, const EntryKey &key) const {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
|
||||
Position pos = 0;
|
||||
RomDirectoryEntry entry = {};
|
||||
R_TRY(this->GetDirectoryEntry(std::addressof(pos), std::addressof(entry), key));
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result OpenFile(FileInfo *out, const EntryKey &key) const {
|
||||
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 FindOpen(FindPosition *out, const EntryKey &key) const {
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -1,367 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/fssystem/fssystem_dbm_rom_types.hpp>
|
||||
|
||||
namespace ams::fssystem {
|
||||
|
||||
constexpr ALWAYS_INLINE u32 AlignRomAddress(u32 addr) {
|
||||
return util::AlignUp(addr, sizeof(addr));
|
||||
}
|
||||
|
||||
template<typename BucketStorageType, typename EntryStorageType, typename KeyType, typename ValueType, size_t MaxAuxiliarySize>
|
||||
class RomKeyValueStorage {
|
||||
public:
|
||||
using BucketStorage = BucketStorageType;
|
||||
using EntryStorage = EntryStorageType;
|
||||
using Key = KeyType;
|
||||
using Value = ValueType;
|
||||
using Position = u32;
|
||||
using BucketIndex = u32;
|
||||
|
||||
struct FindIndex {
|
||||
BucketIndex ind;
|
||||
Position pos;
|
||||
};
|
||||
static_assert(util::is_pod<FindIndex>::value);
|
||||
private:
|
||||
static constexpr inline Position InvalidPosition = ~Position();
|
||||
|
||||
struct Element {
|
||||
Key key;
|
||||
Value value;
|
||||
Position next;
|
||||
u32 size;
|
||||
};
|
||||
static_assert(util::is_pod<Element>::value);
|
||||
private:
|
||||
s64 bucket_offset;
|
||||
u32 bucket_count;
|
||||
BucketStorage *bucket_storage;
|
||||
s64 kv_offset;
|
||||
u32 kv_size;
|
||||
EntryStorage *kv_storage;
|
||||
u32 total_entry_size;
|
||||
u32 entry_count;
|
||||
public:
|
||||
static constexpr u32 QueryEntrySize(u32 aux_size) {
|
||||
return AlignRomAddress(sizeof(Element) + aux_size);
|
||||
}
|
||||
|
||||
static constexpr u32 QueryBucketStorageSize(u32 num) {
|
||||
return num * sizeof(Position);
|
||||
}
|
||||
|
||||
static constexpr u32 QueryBucketCount(u32 size) {
|
||||
return size / sizeof(Position);
|
||||
}
|
||||
|
||||
static constexpr u32 QueryKeyValueStorageSize(u32 num) {
|
||||
return num * sizeof(Element);
|
||||
}
|
||||
|
||||
static Result Format(BucketStorage *bucket, s64 bucket_ofs, u32 bucket_count, EntryStorage *kv, s64 kv_ofs, u32 kv_size) {
|
||||
AMS_ASSERT(bucket != nullptr);
|
||||
AMS_ASSERT(kv != nullptr);
|
||||
AMS_ASSERT(kv_size >= 0);
|
||||
|
||||
const Position pos = InvalidPosition;
|
||||
for (s64 i = 0; i < bucket_count; i++) {
|
||||
R_TRY(bucket->Write(bucket_ofs + i * sizeof(pos), std::addressof(pos), sizeof(pos)));
|
||||
}
|
||||
return ResultSuccess();
|
||||
}
|
||||
public:
|
||||
RomKeyValueStorage() : bucket_offset(), bucket_count(), bucket_storage(), kv_offset(), kv_size(), kv_storage(), total_entry_size(), entry_count() { /* ... */ }
|
||||
|
||||
Result Initialize(BucketStorage *bucket, s64 bucket_ofs, u32 bucket_count, EntryStorage *kv, s64 kv_ofs, u32 kv_size) {
|
||||
AMS_ASSERT(bucket != nullptr);
|
||||
AMS_ASSERT(kv != nullptr);
|
||||
AMS_ASSERT(bucket_count > 0);
|
||||
|
||||
this->bucket_storage = bucket;
|
||||
this->bucket_offset = bucket_ofs;
|
||||
this->bucket_count = bucket_count;
|
||||
|
||||
this->kv_storage = kv;
|
||||
this->kv_offset = kv_ofs;
|
||||
this->kv_size = kv_size;
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void Finalize() {
|
||||
this->bucket_storage = nullptr;
|
||||
this->bucket_offset = 0;
|
||||
this->bucket_count = 0;
|
||||
|
||||
this->kv_storage = nullptr;
|
||||
this->kv_offset = 0;
|
||||
this->kv_size = 0;
|
||||
}
|
||||
|
||||
constexpr u32 GetTotalEntrySize() const {
|
||||
return this->total_entry_size;
|
||||
}
|
||||
|
||||
constexpr u32 GetFreeSize() const {
|
||||
return (this->kv_size - this->total_entry_size);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void FindOpen(FindIndex *out) const {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
|
||||
out->ind = static_cast<BucketIndex>(-1);
|
||||
out->pos = InvalidPosition;
|
||||
}
|
||||
|
||||
Result FindNext(Key *out_key, Value *out_val, FindIndex *find) {
|
||||
AMS_ASSERT(out_key != nullptr);
|
||||
AMS_ASSERT(out_val != nullptr);
|
||||
AMS_ASSERT(find != nullptr);
|
||||
|
||||
Element elem;
|
||||
|
||||
BucketIndex ind = find->ind;
|
||||
R_UNLESS((ind < this->bucket_count) || ind == static_cast<BucketIndex>(-1), fs::ResultDbmFindKeyFinished());
|
||||
|
||||
while (true) {
|
||||
if (find->pos != InvalidPosition) {
|
||||
R_TRY(this->ReadKeyValue(std::addressof(elem), nullptr, nullptr, find->pos));
|
||||
|
||||
AMS_ASSERT(elem.next == InvalidPosition || elem.next < this->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 < this->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) {
|
||||
Position pos, prev_pos;
|
||||
Element elem;
|
||||
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(this->bucket_count > 0);
|
||||
AMS_ASSERT(this->kv_size >= 0);
|
||||
|
||||
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);
|
||||
|
||||
R_TRY(this->AllocateEntry(std::addressof(pos), aux_size));
|
||||
|
||||
Position next_pos;
|
||||
R_TRY(this->LinkEntry(std::addressof(next_pos), pos, hash_key));
|
||||
|
||||
elem = { key, value, next_pos, static_cast<u32>(aux_size) };
|
||||
*out = pos;
|
||||
R_TRY(this->WriteKeyValue(std::addressof(elem), pos, aux, aux_size, fs::WriteOption::None));
|
||||
|
||||
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) const {
|
||||
Position pos, prev_pos;
|
||||
Element elem;
|
||||
|
||||
AMS_ASSERT(out_pos != nullptr);
|
||||
AMS_ASSERT(out_val != nullptr);
|
||||
|
||||
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, void *out_aux, size_t *out_aux_size, Position pos) const {
|
||||
AMS_ASSERT(out_key != nullptr);
|
||||
AMS_ASSERT(out_val != 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, fs::WriteOption option) const {
|
||||
Element elem;
|
||||
R_TRY(this->ReadKeyValue(std::addressof(elem), nullptr, nullptr, pos));
|
||||
elem.value = value;
|
||||
return this->WriteKeyValue(std::addressof(elem), pos, nullptr, 0, option);
|
||||
}
|
||||
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) const {
|
||||
AMS_ASSERT(out_pos != nullptr);
|
||||
AMS_ASSERT(out_prev != nullptr);
|
||||
AMS_ASSERT(out_elem != nullptr);
|
||||
AMS_ASSERT(this->bucket_count > 0);
|
||||
AMS_ASSERT(this->kv_size >= 0);
|
||||
|
||||
*out_pos = 0;
|
||||
*out_prev = 0;
|
||||
|
||||
const BucketIndex ind = HashToBucket(hash_key);
|
||||
|
||||
Position cur;
|
||||
R_TRY(this->ReadBucket(std::addressof(cur), ind));
|
||||
AMS_ASSERT(cur == InvalidPosition || cur < this->kv_size);
|
||||
|
||||
R_UNLESS(cur != InvalidPosition, fs::ResultDbmKeyNotFound());
|
||||
|
||||
u8 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);
|
||||
|
||||
R_UNLESS(this->total_entry_size + sizeof(Element) + aux_size <= this->kv_size, fs::ResultDbmKeyFull());
|
||||
|
||||
*out = static_cast<Position>(this->total_entry_size);
|
||||
|
||||
this->total_entry_size = AlignRomAddress(this->total_entry_size + sizeof(Element) + static_cast<u32>(aux_size));
|
||||
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));
|
||||
AMS_ASSERT(next == InvalidPosition || next < this->kv_size);
|
||||
|
||||
R_TRY(this->WriteBucket(pos, ind, fs::WriteOption::None));
|
||||
|
||||
*out = next;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ReadBucket(Position *out, BucketIndex ind) const {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(this->bucket_storage != nullptr);
|
||||
AMS_ASSERT(ind < this->bucket_count);
|
||||
|
||||
const s64 offset = this->bucket_offset + ind * sizeof(Position);
|
||||
return this->bucket_storage->Read(offset, out, sizeof(*out));
|
||||
}
|
||||
|
||||
Result WriteBucket(Position pos, BucketIndex ind, fs::WriteOption option) const {
|
||||
AMS_ASSERT(this->bucket_storage != nullptr);
|
||||
AMS_ASSERT(ind < this->bucket_count);
|
||||
|
||||
const s64 offset = this->bucket_offset + ind * sizeof(Position);
|
||||
return this->bucket_storage.Write(offset, std::addressof(pos), sizeof(pos));
|
||||
}
|
||||
|
||||
Result ReadKeyValue(Element *out, void *out_aux, size_t *out_aux_size, Position pos) const {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(this->kv_storage != nullptr);
|
||||
AMS_ASSERT(pos < this->kv_size);
|
||||
|
||||
const s64 offset = this->kv_offset + pos;
|
||||
R_TRY(this->kv_storage->Read(offset, out, sizeof(*out)));
|
||||
|
||||
if (out_aux != nullptr && out_aux_size != nullptr) {
|
||||
*out_aux_size = out->size;
|
||||
if (out->size > 0) {
|
||||
R_TRY(this->kv_storage->Read(offset + sizeof(*out), out_aux, out->size));
|
||||
}
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result WriteKeyValue(const Element *elem, Position pos, const void *aux, size_t aux_size, fs::WriteOption option) const {
|
||||
AMS_ASSERT(elem != nullptr);
|
||||
AMS_ASSERT(this->kv_storage != nullptr);
|
||||
AMS_ASSERT(pos < this->kv_size);
|
||||
|
||||
const s64 offset = this->kv_offset + pos;
|
||||
R_TRY(this->kv_storage->Write(offset, elem, sizeof(*elem)));
|
||||
|
||||
if (aux != nullptr && aux_size > 0) {
|
||||
R_TRY(this->kv_storage->Write(offset + sizeof(*elem), aux, aux_size));
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere/fssystem/fssystem_dbm_rom_types.hpp>
|
||||
|
||||
namespace ams::fssystem {
|
||||
|
||||
namespace RomPathTool {
|
||||
|
||||
constexpr inline u32 MaxPathLength = 0x300;
|
||||
|
||||
struct RomEntryName {
|
||||
size_t length;
|
||||
const RomPathChar *path;
|
||||
};
|
||||
static_assert(util::is_pod<RomEntryName>::value);
|
||||
|
||||
constexpr void InitializeRomEntryName(RomEntryName *entry) {
|
||||
entry->length = 0;
|
||||
}
|
||||
|
||||
constexpr inline bool IsSeparator(RomPathChar c) {
|
||||
return c == RomStringTraits::DirectorySeparator;
|
||||
}
|
||||
|
||||
constexpr inline bool IsNullTerminator(RomPathChar c) {
|
||||
return c == RomStringTraits::NullTerminator;
|
||||
}
|
||||
|
||||
constexpr inline bool IsDot(RomPathChar c) {
|
||||
return c == RomStringTraits::Dot;
|
||||
}
|
||||
|
||||
constexpr inline bool IsCurrentDirectory(const RomEntryName &name) {
|
||||
return name.length == 1 && IsDot(name.path[0]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsCurrentDirectory(const RomPathChar *p, size_t length) {
|
||||
return length == 1 && IsDot(p[0]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsCurrentDirectory(const RomPathChar *p) {
|
||||
return IsDot(p[0]) && IsNullTerminator(p[1]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsParentDirectory(const RomEntryName &name) {
|
||||
return name.length == 2 && IsDot(name.path[0]) && IsDot(name.path[1]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsParentDirectory(const RomPathChar *p) {
|
||||
return IsDot(p[0]) && IsDot(p[1]) && IsNullTerminator(p[2]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsParentDirectory(const RomPathChar *p, size_t length) {
|
||||
return length == 2 && IsDot(p[0]) && IsDot(p[1]);
|
||||
}
|
||||
|
||||
constexpr inline bool IsEqualPath(const RomPathChar *lhs, const RomPathChar *rhs, size_t length) {
|
||||
return std::strncmp(lhs, rhs, length) == 0;
|
||||
}
|
||||
|
||||
constexpr inline bool IsEqualName(const RomEntryName &lhs, const RomPathChar *rhs) {
|
||||
if (strnlen(rhs, MaxPathLength) != lhs.length) {
|
||||
return false;
|
||||
}
|
||||
return IsEqualPath(lhs.path, rhs, lhs.length);
|
||||
}
|
||||
|
||||
constexpr inline bool IsEqualName(const RomEntryName &lhs, const RomEntryName &rhs) {
|
||||
if (lhs.length != rhs.length) {
|
||||
return false;
|
||||
}
|
||||
return IsEqualPath(lhs.path, rhs.path, lhs.length);
|
||||
}
|
||||
|
||||
Result GetParentDirectoryName(RomEntryName *out, const RomEntryName &cur, const RomPathChar *p);
|
||||
|
||||
class PathParser {
|
||||
private:
|
||||
const RomPathChar *prev_path_start;
|
||||
const RomPathChar *prev_path_end;
|
||||
const RomPathChar *next_path;
|
||||
bool finished;
|
||||
public:
|
||||
constexpr PathParser() : prev_path_start(), prev_path_end(), next_path(), finished() { /* ... */ }
|
||||
|
||||
Result Initialize(const RomPathChar *path);
|
||||
void Finalize();
|
||||
|
||||
bool IsFinished() const;
|
||||
bool IsDirectoryPath() const;
|
||||
|
||||
Result GetAsDirectoryName(RomEntryName *out) const;
|
||||
Result GetAsFileName(RomEntryName *out) const;
|
||||
|
||||
Result GetNextDirectoryName(RomEntryName *out);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere/fs/fs_common.hpp>
|
||||
|
||||
namespace ams::fssystem {
|
||||
|
||||
using RomPathChar = char;
|
||||
using RomFileId = s32;
|
||||
using RomDirectoryId = s32;
|
||||
|
||||
struct RomFileSystemInformation {
|
||||
s64 size;
|
||||
s64 directory_bucket_offset;
|
||||
s64 directory_bucket_size;
|
||||
s64 directory_entry_offset;
|
||||
s64 directory_entry_size;
|
||||
s64 file_bucket_offset;
|
||||
s64 file_bucket_size;
|
||||
s64 file_entry_offset;
|
||||
s64 file_entry_size;
|
||||
s64 body_offset;
|
||||
};
|
||||
static_assert(util::is_pod<RomFileSystemInformation>::value);
|
||||
static_assert(sizeof(RomFileSystemInformation) == 0x50);
|
||||
|
||||
struct RomDirectoryInfo {
|
||||
/* ... */
|
||||
};
|
||||
static_assert(util::is_pod<RomDirectoryInfo>::value);
|
||||
|
||||
struct RomFileInfo {
|
||||
fs::Int64 offset;
|
||||
fs::Int64 size;
|
||||
};
|
||||
static_assert(util::is_pod<RomFileInfo>::value);
|
||||
|
||||
namespace RomStringTraits {
|
||||
|
||||
constexpr inline char DirectorySeparator = '/';
|
||||
constexpr inline char NullTerminator = '\x00';
|
||||
constexpr inline char Dot = '.';
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -17,7 +17,7 @@
|
|||
#include <vapours.hpp>
|
||||
#include <stratosphere/fs/fsa/fs_ifilesystem.hpp>
|
||||
#include <stratosphere/fs/impl/fs_newable.hpp>
|
||||
#include <stratosphere/fssystem/fssystem_dbm_hierarchical_rom_file_table.hpp>
|
||||
#include <stratosphere/fs/common/fs_dbm_hierarchical_rom_file_table.hpp>
|
||||
#include <stratosphere/fs/fs_istorage.hpp>
|
||||
|
||||
namespace ams::fssystem {
|
||||
|
@ -25,7 +25,7 @@ namespace ams::fssystem {
|
|||
class RomFsFileSystem : public fs::fsa::IFileSystem, public fs::impl::Newable {
|
||||
NON_COPYABLE(RomFsFileSystem);
|
||||
public:
|
||||
using RomFileTable = HierarchicalRomFileTable<fs::IStorage, fs::IStorage, fs::IStorage, fs::IStorage>;
|
||||
using RomFileTable = fs::HierarchicalRomFileTable;
|
||||
private:
|
||||
RomFileTable rom_file_table;
|
||||
fs::IStorage *base_storage;
|
||||
|
|
|
@ -17,23 +17,22 @@
|
|||
|
||||
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);
|
||||
size_t HierarchicalRomFileTable::QueryDirectoryEntrySize(size_t aux_size) {
|
||||
return DirectoryEntryMapTable::QueryEntrySize(aux_size);
|
||||
}
|
||||
|
||||
s64 HierarchicalRomFileTable::QueryFileEntryBucketStorageSize(s64 count) {
|
||||
return FileEntryMapTable::QueryBucketStorageSize(count);
|
||||
}
|
||||
|
||||
size_t HierarchicalRomFileTable::QueryFileEntrySize(size_t aux_size) {
|
||||
return FileEntryMapTable::QueryEntrySize(aux_size);
|
||||
}
|
||||
|
||||
Result HierarchicalRomFileTable::Format(SubStorage dir_bucket, SubStorage file_bucket) {
|
||||
s64 dir_bucket_size;
|
||||
R_TRY(dir_bucket.GetSize(std::addressof(dir_bucket_size)));
|
||||
|
@ -69,7 +68,7 @@ namespace ams::fs {
|
|||
Position root_pos = RootPosition;
|
||||
EntryKey root_key = {};
|
||||
root_key.key.parent = root_pos;
|
||||
RomPathTool::InitializeRomEntryName(std::addressof(root_key.name));
|
||||
RomPathTool::InitEntryName(std::addressof(root_key.name));
|
||||
RomDirectoryEntry root_entry = {
|
||||
.next = InvalidPosition,
|
||||
.dir = InvalidPosition,
|
||||
|
@ -99,7 +98,7 @@ namespace ams::fs {
|
|||
R_CONVERT(fs::ResultDbmKeyFull, fs::ResultDbmDirectoryEntryFull())
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
*out = ConvertToDirectoryId(new_pos);
|
||||
*out = PositionToDirectoryId(new_pos);
|
||||
|
||||
if (parent_entry.dir == InvalidPosition) {
|
||||
parent_entry.dir = new_pos;
|
||||
|
@ -146,7 +145,7 @@ namespace ams::fs {
|
|||
R_CONVERT(fs::ResultDbmKeyFull, fs::ResultDbmFileEntryFull())
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
*out = ConvertToFileId(new_pos);
|
||||
*out = PositionToFileId(new_pos);
|
||||
|
||||
if (parent_entry.file == InvalidPosition) {
|
||||
parent_entry.file = new_pos;
|
||||
|
@ -185,7 +184,7 @@ namespace ams::fs {
|
|||
RomDirectoryEntry entry = {};
|
||||
R_TRY(this->GetDirectoryEntry(std::addressof(pos), std::addressof(entry), key));
|
||||
|
||||
*out = ConvertToDirectoryId(pos);
|
||||
*out = PositionToDirectoryId(pos);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
|
@ -201,7 +200,7 @@ namespace ams::fs {
|
|||
RomFileEntry entry = {};
|
||||
R_TRY(this->GetFileEntry(std::addressof(pos), std::addressof(entry), key));
|
||||
|
||||
*out = ConvertToFileId(pos);
|
||||
*out = PositionToFileId(pos);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
|
@ -353,7 +352,7 @@ namespace ams::fs {
|
|||
R_TRY(this->GetDirectoryEntry(std::addressof(dir_pos), std::addressof(dir_entry), dir_key));
|
||||
|
||||
Position parent_pos = dir_pos;
|
||||
while (!parser->IsFinished()) {
|
||||
while (!parser->IsParseFinished()) {
|
||||
EntryKey old_key = dir_key;
|
||||
|
||||
R_TRY(parser->GetNextDirectoryName(std::addressof(dir_key.name)));
|
||||
|
@ -492,7 +491,7 @@ namespace ams::fs {
|
|||
|
||||
Result HierarchicalRomFileTable::GetDirectoryEntry(RomDirectoryEntry *out_entry, RomDirectoryId id) {
|
||||
AMS_ASSERT(out_entry != nullptr);
|
||||
Position pos = ConvertToPosition(id);
|
||||
Position pos = DirectoryIdToPosition(id);
|
||||
|
||||
RomEntryKey key = {};
|
||||
const Result dir_res = this->dir_table.GetByPosition(std::addressof(key), out_entry, pos);
|
||||
|
@ -524,7 +523,7 @@ namespace ams::fs {
|
|||
|
||||
Result HierarchicalRomFileTable::GetFileEntry(RomFileEntry *out_entry, RomFileId id) {
|
||||
AMS_ASSERT(out_entry != nullptr);
|
||||
Position pos = ConvertToPosition(id);
|
||||
Position pos = FileIdToPosition(id);
|
||||
|
||||
RomEntryKey key = {};
|
||||
const Result file_res = this->file_table.GetByPosition(std::addressof(key), out_entry, pos);
|
|
@ -28,9 +28,8 @@ namespace ams::fs::RomPathTool {
|
|||
|
||||
this->prev_path_start = path;
|
||||
this->prev_path_end = path;
|
||||
this->next_path = path + 1;
|
||||
while (IsSeparator(this->next_path[0])) {
|
||||
this->next_path++;
|
||||
for (this->next_path = path + 1; IsSeparator(this->next_path[0]); ++this->next_path) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
|
@ -43,12 +42,13 @@ namespace ams::fs::RomPathTool {
|
|||
this->finished = false;
|
||||
}
|
||||
|
||||
bool PathParser::IsFinished() const {
|
||||
bool PathParser::IsParseFinished() const {
|
||||
return this->finished;
|
||||
}
|
||||
|
||||
bool PathParser::IsDirectoryPath() const {
|
||||
AMS_ASSERT(this->next_path != nullptr);
|
||||
|
||||
if (IsNullTerminator(this->next_path[0]) && IsSeparator(this->next_path[-1])) {
|
||||
return true;
|
||||
}
|
||||
|
@ -57,11 +57,47 @@ namespace ams::fs::RomPathTool {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (IsParentDirectory(this->next_path)) {
|
||||
return true;
|
||||
return IsParentDirectory(this->next_path);
|
||||
}
|
||||
|
||||
return false;
|
||||
Result PathParser::GetNextDirectoryName(RomEntryName *out) {
|
||||
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;
|
||||
out->path = this->prev_path_start;
|
||||
|
||||
/* Parse the next path. */
|
||||
this->prev_path_start = this->next_path;
|
||||
const RomPathChar *cur = this->next_path;
|
||||
for (size_t name_len = 0; true; name_len++) {
|
||||
if (IsSeparator(cur[name_len])) {
|
||||
R_UNLESS(name_len < MaxPathLength, fs::ResultDbmDirectoryNameTooLong());
|
||||
|
||||
this->prev_path_end = cur + name_len;
|
||||
this->next_path = this->prev_path_end + 1;
|
||||
|
||||
while (IsSeparator(this->next_path[0])) {
|
||||
++this->next_path;
|
||||
}
|
||||
if (IsNullTerminator(this->next_path[0])) {
|
||||
this->finished = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (IsNullTerminator(cur[name_len])) {
|
||||
this->finished = true;
|
||||
this->next_path = cur + name_len;
|
||||
this->prev_path_end = cur + name_len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result PathParser::GetAsDirectoryName(RomEntryName *out) const {
|
||||
|
@ -92,45 +128,6 @@ namespace ams::fs::RomPathTool {
|
|||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result PathParser::GetNextDirectoryName(RomEntryName *out) {
|
||||
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;
|
||||
out->path = this->prev_path_start;
|
||||
|
||||
/* Parse the next path. */
|
||||
this->prev_path_start = this->next_path;
|
||||
const RomPathChar *cur = this->next_path;
|
||||
for (size_t name_len = 0; true; name_len++) {
|
||||
if (IsSeparator(cur[name_len])) {
|
||||
R_UNLESS(name_len < MaxPathLength, fs::ResultDbmDirectoryNameTooLong());
|
||||
|
||||
this->prev_path_end = cur + name_len;
|
||||
this->next_path = this->prev_path_end + 1;
|
||||
|
||||
while (IsSeparator(this->next_path[0])) {
|
||||
this->next_path++;
|
||||
}
|
||||
if (IsNullTerminator(this->next_path[0])) {
|
||||
this->finished = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (IsNullTerminator(cur[name_len])) {
|
||||
this->finished = true;
|
||||
this->prev_path_end = this->next_path = cur + name_len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetParentDirectoryName(RomEntryName *out, const RomEntryName &cur, const RomPathChar *p) {
|
||||
AMS_ASSERT(out != nullptr);
|
||||
AMS_ASSERT(p != nullptr);
|
||||
|
@ -140,7 +137,7 @@ namespace ams::fs::RomPathTool {
|
|||
|
||||
s32 depth = 1;
|
||||
if (IsParentDirectory(cur)) {
|
||||
depth++;
|
||||
++depth;
|
||||
}
|
||||
|
||||
if (cur.path > p) {
|
||||
|
@ -149,7 +146,7 @@ namespace ams::fs::RomPathTool {
|
|||
while (head >= p) {
|
||||
if (IsSeparator(*head)) {
|
||||
if (IsCurrentDirectory(head + 1, len)) {
|
||||
depth++;
|
||||
++depth;
|
||||
}
|
||||
|
||||
if (IsParentDirectory(head + 1, len)) {
|
||||
|
@ -162,16 +159,16 @@ namespace ams::fs::RomPathTool {
|
|||
}
|
||||
|
||||
while (IsSeparator(*head)) {
|
||||
head--;
|
||||
--head;
|
||||
}
|
||||
|
||||
end = head;
|
||||
len = 0;
|
||||
depth--;
|
||||
--depth;
|
||||
}
|
||||
|
||||
len++;
|
||||
head--;
|
||||
++len;
|
||||
--head;
|
||||
}
|
||||
|
||||
R_UNLESS(depth == 0, fs::ResultDirectoryUnobtainable());
|
|
@ -316,7 +316,7 @@ namespace ams::fs {
|
|||
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)));
|
||||
R_TRY(this->parent->GetRomFileTable()->OpenFile(std::addressof(file_info), this->parent->GetRomFileTable()->PositionToFileId(file_pos)));
|
||||
out_entries[i].file_size = file_info.size.Get();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,189 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::fssystem::RomPathTool {
|
||||
|
||||
Result PathParser::Initialize(const RomPathChar *path) {
|
||||
AMS_ASSERT(path != nullptr);
|
||||
|
||||
/* Require paths start with a separator, and skip repeated separators. */
|
||||
R_UNLESS(IsSeparator(path[0]), fs::ResultDbmInvalidPathFormat());
|
||||
while (IsSeparator(path[1])) {
|
||||
path++;
|
||||
}
|
||||
|
||||
this->prev_path_start = path;
|
||||
this->prev_path_end = path;
|
||||
this->next_path = path + 1;
|
||||
while (IsSeparator(this->next_path[0])) {
|
||||
this->next_path++;
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void PathParser::Finalize() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
bool PathParser::IsFinished() const {
|
||||
return this->finished;
|
||||
}
|
||||
|
||||
bool PathParser::IsDirectoryPath() const {
|
||||
AMS_ASSERT(this->next_path != nullptr);
|
||||
if (IsNullTerminator(this->next_path[0]) && IsSeparator(this->next_path[-1])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsCurrentDirectory(this->next_path)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsParentDirectory(this->next_path)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Result PathParser::GetAsDirectoryName(RomEntryName *out) const {
|
||||
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());
|
||||
|
||||
out->length = len;
|
||||
out->path = this->prev_path_start;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result PathParser::GetAsFileName(RomEntryName *out) const {
|
||||
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());
|
||||
|
||||
out->length = len;
|
||||
out->path = this->prev_path_start;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result PathParser::GetNextDirectoryName(RomEntryName *out) {
|
||||
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;
|
||||
out->path = this->prev_path_start;
|
||||
|
||||
/* Parse the next path. */
|
||||
this->prev_path_start = this->next_path;
|
||||
const RomPathChar *cur = this->next_path;
|
||||
for (size_t name_len = 0; true; name_len++) {
|
||||
if (IsSeparator(cur[name_len])) {
|
||||
R_UNLESS(name_len < MaxPathLength, fs::ResultDbmDirectoryNameTooLong());
|
||||
|
||||
this->prev_path_end = cur + name_len;
|
||||
this->next_path = this->prev_path_end + 1;
|
||||
|
||||
while (IsSeparator(this->next_path[0])) {
|
||||
this->next_path++;
|
||||
}
|
||||
if (IsNullTerminator(this->next_path[0])) {
|
||||
this->finished = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (IsNullTerminator(cur[name_len])) {
|
||||
this->finished = true;
|
||||
this->prev_path_end = this->next_path = cur + name_len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetParentDirectoryName(RomEntryName *out, const RomEntryName &cur, const RomPathChar *p) {
|
||||
const RomPathChar *start = cur.path;
|
||||
const RomPathChar *end = cur.path + cur.length - 1;
|
||||
|
||||
s32 depth = 1;
|
||||
if (IsParentDirectory(cur)) {
|
||||
depth++;
|
||||
}
|
||||
|
||||
if (cur.path > p) {
|
||||
size_t len = 0;
|
||||
const RomPathChar *head = cur.path - 1;
|
||||
while (head >= p) {
|
||||
if (IsSeparator(*head)) {
|
||||
if (IsCurrentDirectory(head + 1, len)) {
|
||||
depth++;
|
||||
}
|
||||
|
||||
if (IsParentDirectory(head + 1, len)) {
|
||||
depth += 2;
|
||||
}
|
||||
|
||||
if (depth == 0) {
|
||||
start = head + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
while (IsSeparator(*head)) {
|
||||
head--;
|
||||
}
|
||||
|
||||
end = head;
|
||||
len = 0;
|
||||
depth--;
|
||||
}
|
||||
|
||||
len++;
|
||||
head--;
|
||||
}
|
||||
|
||||
R_UNLESS(depth == 0, fs::ResultDbmInvalidPathFormat());
|
||||
|
||||
if (head == p) {
|
||||
start = p + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (end <= p) {
|
||||
out->path = p;
|
||||
out->length = 0;
|
||||
} else {
|
||||
out->path = start;
|
||||
out->length = end - start + 1;
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
|
@ -19,7 +19,7 @@ namespace ams::fssystem {
|
|||
|
||||
namespace {
|
||||
|
||||
constexpr size_t CalculateRequiredWorkingMemorySize(const RomFileSystemInformation &header) {
|
||||
constexpr size_t CalculateRequiredWorkingMemorySize(const fs::RomFileSystemInformation &header) {
|
||||
return header.directory_bucket_size + header.directory_entry_size + header.file_bucket_size + header.file_entry_size;
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,7 @@ namespace ams::fssystem {
|
|||
public:
|
||||
virtual Result ReadImpl(s64 *out_count, fs::DirectoryEntry *out_entries, s64 max_entries) {
|
||||
R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([=, this]() -> Result {
|
||||
return this->ReadImpl(out_count, std::addressof(this->current_find), out_entries, max_entries);
|
||||
return this->ReadInternal(out_count, std::addressof(this->current_find), out_entries, max_entries);
|
||||
}, AMS_CURRENT_FUNCTION_NAME));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
@ -123,20 +123,20 @@ namespace ams::fssystem {
|
|||
FindPosition find = this->first_find;
|
||||
|
||||
R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([&]() -> Result {
|
||||
R_TRY(this->ReadImpl(out, std::addressof(find), nullptr, 0));
|
||||
R_TRY(this->ReadInternal(out, std::addressof(find), nullptr, 0));
|
||||
return ResultSuccess();
|
||||
}, AMS_CURRENT_FUNCTION_NAME));
|
||||
return ResultSuccess();
|
||||
}
|
||||
private:
|
||||
Result ReadImpl(s64 *out_count, FindPosition *find, fs::DirectoryEntry *out_entries, s64 max_entries) {
|
||||
Result ReadInternal(s64 *out_count, FindPosition *find, fs::DirectoryEntry *out_entries, s64 max_entries) {
|
||||
constexpr size_t NameBufferSize = fs::EntryNameLengthMax + 1;
|
||||
RomPathChar name[NameBufferSize];
|
||||
fs::RomPathChar name[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, find)) {
|
||||
R_TRY_CATCH(this->parent->GetRomFileTable()->FindNextDirectory(name, find, NameBufferSize)) {
|
||||
R_CATCH(fs::ResultDbmFindFinished) { break; }
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
|
@ -156,7 +156,7 @@ namespace ams::fssystem {
|
|||
while (i < max_entries || out_entries == nullptr) {
|
||||
auto file_pos = find->next_file;
|
||||
|
||||
R_TRY_CATCH(this->parent->GetRomFileTable()->FindNextFile(name, find)) {
|
||||
R_TRY_CATCH(this->parent->GetRomFileTable()->FindNextFile(name, find, NameBufferSize)) {
|
||||
R_CATCH(fs::ResultDbmFindFinished) { break; }
|
||||
} R_END_TRY_CATCH;
|
||||
|
||||
|
@ -167,7 +167,7 @@ namespace ams::fssystem {
|
|||
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)));
|
||||
R_TRY(this->parent->GetRomFileTable()->OpenFile(std::addressof(file_info), this->parent->GetRomFileTable()->PositionToFileId(file_pos)));
|
||||
out_entries[i].file_size = file_info.size.Get();
|
||||
}
|
||||
|
||||
|
@ -204,7 +204,7 @@ namespace ams::fssystem {
|
|||
}
|
||||
|
||||
Result RomFsFileSystem::GetRequiredWorkingMemorySize(size_t *out, fs::IStorage *storage) {
|
||||
RomFileSystemInformation header;
|
||||
fs::RomFileSystemInformation header;
|
||||
|
||||
R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([&]() -> Result {
|
||||
R_TRY(storage->Read(0, std::addressof(header), sizeof(header)));
|
||||
|
@ -224,7 +224,7 @@ namespace ams::fssystem {
|
|||
buffers::EnableBlockingBufferManagerAllocation();
|
||||
|
||||
/* Read the header. */
|
||||
RomFileSystemInformation header;
|
||||
fs::RomFileSystemInformation header;
|
||||
R_TRY(base->Read(0, std::addressof(header), sizeof(header)));
|
||||
|
||||
/* Set up our storages. */
|
||||
|
@ -261,10 +261,10 @@ namespace ams::fssystem {
|
|||
R_UNLESS(this->file_entry_storage != nullptr, fs::ResultAllocationFailureInRomFsFileSystemB());
|
||||
|
||||
/* Initialize the rom table. */
|
||||
R_TRY(this->rom_file_table.Initialize(this->dir_bucket_storage.get(), 0, static_cast<u32>(header.directory_bucket_size),
|
||||
this->dir_entry_storage.get(), 0, static_cast<u32>(header.directory_entry_size),
|
||||
this->file_bucket_storage.get(), 0, static_cast<u32>(header.file_bucket_size),
|
||||
this->file_entry_storage.get(), 0, static_cast<u32>(header.file_entry_size)));
|
||||
R_TRY(this->rom_file_table.Initialize(fs::SubStorage(this->dir_bucket_storage.get(), 0, static_cast<u32>(header.directory_bucket_size)),
|
||||
fs::SubStorage(this->dir_entry_storage.get(), 0, static_cast<u32>(header.directory_entry_size)),
|
||||
fs::SubStorage(this->file_bucket_storage.get(), 0, static_cast<u32>(header.file_bucket_size)),
|
||||
fs::SubStorage(this->file_entry_storage.get(), 0, static_cast<u32>(header.file_entry_size))));
|
||||
|
||||
/* Set members. */
|
||||
this->entry_size = header.body_offset;
|
||||
|
@ -326,7 +326,7 @@ namespace ams::fssystem {
|
|||
|
||||
Result RomFsFileSystem::GetEntryTypeImpl(fs::DirectoryEntryType *out, const char *path) {
|
||||
R_TRY(buffers::DoContinuouslyUntilBufferIsAllocated([=, this]() -> Result {
|
||||
RomDirectoryInfo dir_info;
|
||||
fs::RomDirectoryInfo dir_info;
|
||||
|
||||
R_TRY_CATCH(this->rom_file_table.GetDirectoryInformation(std::addressof(dir_info), path)) {
|
||||
R_CONVERT(fs::ResultDbmNotFound, fs::ResultPathNotFound())
|
||||
|
|
Loading…
Reference in a new issue