diff --git a/libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_hierarchical_rom_file_table.hpp b/libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_hierarchical_rom_file_table.hpp new file mode 100644 index 0000000..c8cb144 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_hierarchical_rom_file_table.hpp @@ -0,0 +1,204 @@ +/* + * 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 . + */ +#pragma once +#include +#include +#include + +namespace ams::fs { + + class HierarchicalRomFileTable { + public: + using Position = u32; + + struct FindPosition { + Position next_dir; + Position next_file; + }; + static_assert(util::is_pod::value); + + using DirectoryInfo = RomDirectoryInfo; + using FileInfo = RomFileInfo; + + static constexpr RomFileId PositionToFileId(Position pos) { + return static_cast(pos); + } + + static constexpr Position FileIdToPosition(RomFileId id) { + return static_cast(id); + } + private: + static constexpr inline Position InvalidPosition = ~Position(); + static constexpr inline Position RootPosition = 0; + static constexpr inline size_t ReservedDirectoryCount = 1; + + static constexpr RomDirectoryId PositionToDirectoryId(Position pos) { + return static_cast(pos); + } + + static constexpr Position DirectoryIdToPosition(RomDirectoryId id) { + return static_cast(id); + } + + static_assert(std::is_same::value); + + struct RomDirectoryEntry { + Position next; + Position dir; + Position file; + }; + static_assert(util::is_pod::value); + + struct RomFileEntry { + Position next; + FileInfo info; + }; + static_assert(util::is_pod::value); + + static constexpr inline u32 MaxKeyLength = RomPathTool::MaxPathLength; + + template + class EntryMapTable : public KeyValueRomStorageTemplate { + public: + using ImplKey = ImplKeyType; + using ClientKey = ClientKeyType; + using Value = ValueType; + using Position = HierarchicalRomFileTable::Position; + using Base = KeyValueRomStorageTemplate; + public: + Result Add(Position *out, const ClientKeyType &key, const Value &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::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) { + 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(aux_lhs), reinterpret_cast(aux_rhs), aux_lhs_size / sizeof(RomPathChar)); + } + }; + static_assert(util::is_pod::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 * const end = name + this->name.length; + while (name < end) { + const u32 cur = static_cast(static_cast::type>(*(name++))); + hash = ((hash >> 5) | (hash << 27)) ^ cur; + } + return hash; + } + }; + static_assert(util::is_pod::value); + + using DirectoryEntryMapTable = EntryMapTable; + using FileEntryMapTable = EntryMapTable; + private: + DirectoryEntryMapTable dir_table; + FileEntryMapTable file_table; + public: + static s64 QueryDirectoryEntryBucketStorageSize(s64 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: + 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); + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_rom_key_value_storage.hpp b/libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_rom_key_value_storage.hpp new file mode 100644 index 0000000..4acc152 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_rom_key_value_storage.hpp @@ -0,0 +1,314 @@ +/* + * 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 . + */ +#pragma once +#include +#include + +namespace ams::fs { + + template + class KeyValueRomStorageTemplate { + public: + using Key = KeyType; + using Value = ValueType; + using Position = u32; + using BucketIndex = s64; + + struct FindIndex { + BucketIndex ind; + Position pos; + }; + static_assert(util::is_pod::value); + private: + static constexpr inline Position InvalidPosition = ~Position(); + + struct Element { + Key key; + Value value; + Position next; + u32 size; + }; + static_assert(util::is_pod::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 size_t QueryEntrySize(size_t aux_size) { + return util::AlignUp(sizeof(Element) + aux_size, alignof(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: + 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->bucket_count = count; + this->kv_storage = kv; + 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; + } + protected: + 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 || aux_size == 0); + AMS_ASSERT(this->bucket_count > 0); + + { + Position pos, prev_pos; + Element elem; + + 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); + } + + 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(aux_size) }; + R_TRY(this->WriteKeyValue(std::addressof(elem), pos, aux, aux_size)); + + *out = pos; + this->entry_count++; + + return ResultSuccess(); + } + + 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->FindInternal(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 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 || aux_size == 0); + 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(::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(kv_size), fs::ResultDbmKeyFull()); + + *out = static_cast(this->total_entry_size); + + this->total_entry_size = util::AlignUp(static_cast(end_pos), alignof(Position)); + 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(); + } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_rom_path_tool.hpp b/libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_rom_path_tool.hpp new file mode 100644 index 0000000..774feda --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_rom_path_tool.hpp @@ -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 . + */ +#pragma once +#include + +namespace ams::fs::RomPathTool { + + constexpr inline u32 MaxPathLength = 0x300; + + struct RomEntryName { + size_t length; + const RomPathChar *path; + }; + static_assert(util::is_pod::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); + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_rom_types.hpp b/libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_rom_types.hpp new file mode 100644 index 0000000..c4ab66d --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/common/fs_dbm_rom_types.hpp @@ -0,0 +1,59 @@ +/* + * 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 . + */ +#pragma once +#include + +namespace ams::fs { + + 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::value); + static_assert(sizeof(RomFileSystemInformation) == 0x50); + + struct RomDirectoryInfo { + /* ... */ + }; + static_assert(util::is_pod::value); + + struct RomFileInfo { + Int64 offset; + Int64 size; + }; + static_assert(util::is_pod::value); + + namespace RomStringTraits { + + constexpr inline char DirectorySeparator = '/'; + constexpr inline char NullTerminator = '\x00'; + constexpr inline char Dot = '.'; + + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_dbm_hierarchical_rom_file_table.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_dbm_hierarchical_rom_file_table.hpp deleted file mode 100644 index 25651f7..0000000 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_dbm_hierarchical_rom_file_table.hpp +++ /dev/null @@ -1,200 +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 . - */ -#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(util::is_pod::value); - - using DirectoryInfo = RomDirectoryInfo; - using FileInfo = RomFileInfo; - - static constexpr RomFileId ConvertToFileId(Position pos) { - return static_cast(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(pos); - } - - static constexpr Position ConvertToPosition(RomDirectoryId id) { - return static_cast(id); - } - - static_assert(std::is_same::value); - - struct RomDirectoryEntry { - Position next; - Position dir; - Position file; - }; - static_assert(util::is_pod::value); - - struct RomFileEntry { - Position next; - FileInfo info; - }; - static_assert(util::is_pod::value); - - static constexpr inline u32 MaxKeyLength = RomPathTool::MaxPathLength; - - template - class EntryMapTable : public RomKeyValueStorage { - public: - using ImplKey = ImplKeyType; - using ClientKey = ClientKeyType; - using Value = ValueType; - using Position = HierarchicalRomFileTable::Position; - using Base = RomKeyValueStorage; - 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(aux_lhs), reinterpret_cast(aux_rhs), aux_lhs_size / sizeof(RomPathChar)); - } - }; - static_assert(util::is_pod::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(static_cast::type>(*(name++))); - hash = ((hash >> 5) | (hash << 27)) ^ cur; - } - return hash; - } - }; - static_assert(util::is_pod::value); - - using DirectoryEntryMapTable = EntryMapTable; - using FileEntryMapTable = EntryMapTable; - 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); - }; - -} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_dbm_rom_key_value_storage.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_dbm_rom_key_value_storage.hpp deleted file mode 100644 index 455f1cd..0000000 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_dbm_rom_key_value_storage.hpp +++ /dev/null @@ -1,379 +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 . - */ -#pragma once -#include "fs_dbm_rom_types.hpp" -#include "fs_substorage.hpp" - -namespace ams::fs { - - template - class RomKeyValueStorage { - public: - using Key = KeyType; - using Value = ValueType; - using Position = u32; - using BucketIndex = s64; - - struct FindIndex { - BucketIndex ind; - Position pos; - }; - static_assert(util::is_pod::value); - private: - static constexpr inline Position InvalidPosition = ~Position(); - - struct Element { - Key key; - Value value; - Position next; - u32 size; - }; - static_assert(util::is_pod::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); - } - - void FindOpen(FindIndex *out) const { - AMS_ASSERT(out != nullptr); - - out->ind = static_cast(-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(-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(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(::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(kv_size), fs::ResultDbmKeyFull()); - - *out = static_cast(this->total_entry_size); - - this->total_entry_size = util::AlignUp(static_cast(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(); - } - }; - -} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_dbm_rom_path_tool.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_dbm_rom_path_tool.hpp deleted file mode 100644 index 7fc957c..0000000 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_dbm_rom_path_tool.hpp +++ /dev/null @@ -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 . - */ -#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::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); - }; - - } - -} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_dbm_rom_types.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_dbm_rom_types.hpp deleted file mode 100644 index f746af6..0000000 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_dbm_rom_types.hpp +++ /dev/null @@ -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 . - */ -#pragma once -#include "fs_common.hpp" - -namespace ams::fs { - - 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::value); - static_assert(sizeof(RomFileSystemInformation) == 0x50); - - struct RomDirectoryInfo { - /* ... */ - }; - static_assert(util::is_pod::value); - - struct RomFileInfo { - Int64 offset; - Int64 size; - }; - static_assert(util::is_pod::value); - - namespace RomStringTraits { - - constexpr inline char DirectorySeparator = '/'; - constexpr inline char NullTerminator = '\x00'; - constexpr inline char Dot = '.'; - - } - -} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_romfs_filesystem.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_romfs_filesystem.hpp index 36ae471..b986d2a 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_romfs_filesystem.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_romfs_filesystem.hpp @@ -14,12 +14,12 @@ * along with this program. If not, see . */ #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 +#include +#include +#include +#include +#include namespace ams::fs { diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_hierarchical_rom_file_table.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_hierarchical_rom_file_table.hpp deleted file mode 100644 index 390aad1..0000000 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_hierarchical_rom_file_table.hpp +++ /dev/null @@ -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 . - */ -#pragma once -#include -#include -#include -#include - -namespace ams::fssystem { - - template - 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::value); - - using DirectoryInfo = RomDirectoryInfo; - using FileInfo = RomFileInfo; - - static constexpr RomFileId ConvertToFileId(Position pos) { - return static_cast(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(pos); - } - - static constexpr Position ConvertToPosition(RomDirectoryId id) { - return static_cast(id); - } - - static_assert(std::is_same::value); - - struct RomDirectoryEntry { - Position next; - Position dir; - Position file; - }; - static_assert(util::is_pod::value); - - struct RomFileEntry { - Position next; - FileInfo info; - }; - static_assert(util::is_pod::value); - - static constexpr inline u32 MaxKeyLength = RomPathTool::MaxPathLength; - - template - class EntryMapTable : public RomKeyValueStorage { - private: - using BucketStorage = BucketStorageType; - using EntryStorage = EntryStorageType; - public: - using ImplKey = ImplKeyType; - using ClientKey = ClientKeyType; - using Value = ValueType; - using Position = HierarchicalRomFileTable::Position; - using Base = RomKeyValueStorage; - 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(aux_lhs), reinterpret_cast(aux_rhs), aux_lhs_size / sizeof(RomPathChar)); - } - }; - static_assert(util::is_pod::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(static_cast::type>(*(name++))); - hash = ((hash >> 5) | (hash << 27)) ^ cur; - } - return hash; - } - }; - static_assert(util::is_pod::value); - - using DirectoryEntryMapTable = EntryMapTable; - using FileEntryMapTable = EntryMapTable; - 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(); - } - }; - -} diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_rom_key_value_storage.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_rom_key_value_storage.hpp deleted file mode 100644 index 1bbea7a..0000000 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_rom_key_value_storage.hpp +++ /dev/null @@ -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 . - */ -#pragma once -#include -#include - -namespace ams::fssystem { - - constexpr ALWAYS_INLINE u32 AlignRomAddress(u32 addr) { - return util::AlignUp(addr, sizeof(addr)); - } - - template - 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::value); - private: - static constexpr inline Position InvalidPosition = ~Position(); - - struct Element { - Key key; - Value value; - Position next; - u32 size; - }; - static_assert(util::is_pod::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(-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(-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(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(this->total_entry_size); - - this->total_entry_size = AlignRomAddress(this->total_entry_size + sizeof(Element) + static_cast(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(); - } - }; - -} diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_rom_path_tool.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_rom_path_tool.hpp deleted file mode 100644 index 6c40eac..0000000 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_rom_path_tool.hpp +++ /dev/null @@ -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 . - */ -#pragma once -#include - -namespace ams::fssystem { - - namespace RomPathTool { - - constexpr inline u32 MaxPathLength = 0x300; - - struct RomEntryName { - size_t length; - const RomPathChar *path; - }; - static_assert(util::is_pod::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); - }; - - } - -} diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_rom_types.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_rom_types.hpp deleted file mode 100644 index 1baf32e..0000000 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_dbm_rom_types.hpp +++ /dev/null @@ -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 . - */ -#pragma once -#include - -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::value); - static_assert(sizeof(RomFileSystemInformation) == 0x50); - - struct RomDirectoryInfo { - /* ... */ - }; - static_assert(util::is_pod::value); - - struct RomFileInfo { - fs::Int64 offset; - fs::Int64 size; - }; - static_assert(util::is_pod::value); - - namespace RomStringTraits { - - constexpr inline char DirectorySeparator = '/'; - constexpr inline char NullTerminator = '\x00'; - constexpr inline char Dot = '.'; - - } - -} diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_romfs_file_system.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_romfs_file_system.hpp index 34dd760..7067756 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_romfs_file_system.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_romfs_file_system.hpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include namespace ams::fssystem { @@ -25,7 +25,7 @@ class RomFsFileSystem : public fs::fsa::IFileSystem, public fs::impl::Newable { NON_COPYABLE(RomFsFileSystem); public: - using RomFileTable = HierarchicalRomFileTable; + using RomFileTable = fs::HierarchicalRomFileTable; private: RomFileTable rom_file_table; fs::IStorage *base_storage; diff --git a/libraries/libstratosphere/source/fs/common/fs_dbm_hierarchical_rom_file_table.cpp b/libraries/libstratosphere/source/fs/common/fs_dbm_hierarchical_rom_file_table.cpp new file mode 100644 index 0000000..56803bc --- /dev/null +++ b/libraries/libstratosphere/source/fs/common/fs_dbm_hierarchical_rom_file_table.cpp @@ -0,0 +1,577 @@ +/* + * 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 . + */ +#include + +namespace ams::fs { + + s64 HierarchicalRomFileTable::QueryDirectoryEntryBucketStorageSize(s64 count) { + return DirectoryEntryMapTable::QueryBucketStorageSize(count); + } + + 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))); + 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::InitEntryName(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 = PositionToDirectoryId(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 = PositionToFileId(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 = PositionToDirectoryId(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 = PositionToFileId(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->IsParseFinished()) { + 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 = DirectoryIdToPosition(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 = FileIdToPosition(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(); + } + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/fs/common/fs_dbm_rom_path_tool.cpp b/libraries/libstratosphere/source/fs/common/fs_dbm_rom_path_tool.cpp new file mode 100644 index 0000000..9791368 --- /dev/null +++ b/libraries/libstratosphere/source/fs/common/fs_dbm_rom_path_tool.cpp @@ -0,0 +1,192 @@ +/* + * 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 . + */ +#include + +namespace ams::fs::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; + for (this->next_path = path + 1; IsSeparator(this->next_path[0]); ++this->next_path) { + /* ... */ + } + + return ResultSuccess(); + } + + void PathParser::Finalize() { + this->prev_path_start = nullptr; + this->prev_path_end = nullptr; + this->next_path = nullptr; + this->finished = false; + } + + 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; + } + + if (IsCurrentDirectory(this->next_path)) { + return true; + } + + return IsParentDirectory(this->next_path); + } + + 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 { + 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 GetParentDirectoryName(RomEntryName *out, const RomEntryName &cur, const RomPathChar *p) { + AMS_ASSERT(out != nullptr); + AMS_ASSERT(p != nullptr); + + 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::ResultDirectoryUnobtainable()); + + 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(); + } + +} diff --git a/libraries/libstratosphere/source/fs/fs_dbm_hierarchical_rom_file_table.cpp b/libraries/libstratosphere/source/fs/fs_dbm_hierarchical_rom_file_table.cpp deleted file mode 100644 index 56d279b..0000000 --- a/libraries/libstratosphere/source/fs/fs_dbm_hierarchical_rom_file_table.cpp +++ /dev/null @@ -1,578 +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 . - */ -#include - -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(); - } - -} \ No newline at end of file diff --git a/libraries/libstratosphere/source/fs/fs_dbm_rom_path_tool.cpp b/libraries/libstratosphere/source/fs/fs_dbm_rom_path_tool.cpp deleted file mode 100644 index a5f1037..0000000 --- a/libraries/libstratosphere/source/fs/fs_dbm_rom_path_tool.cpp +++ /dev/null @@ -1,195 +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 . - */ -#include - -namespace ams::fs::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() { - this->prev_path_start = nullptr; - this->prev_path_end = nullptr; - this->next_path = nullptr; - this->finished = false; - } - - 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) { - AMS_ASSERT(out != nullptr); - AMS_ASSERT(p != nullptr); - - 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::ResultDirectoryUnobtainable()); - - 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(); - } - -} diff --git a/libraries/libstratosphere/source/fs/fs_romfs_filesystem.cpp b/libraries/libstratosphere/source/fs/fs_romfs_filesystem.cpp index ca6de5b..182fe3e 100644 --- a/libraries/libstratosphere/source/fs/fs_romfs_filesystem.cpp +++ b/libraries/libstratosphere/source/fs/fs_romfs_filesystem.cpp @@ -316,7 +316,7 @@ 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(); } diff --git a/libraries/libstratosphere/source/fssystem/fssystem_dbm_rom_path_tool.cpp b/libraries/libstratosphere/source/fssystem/fssystem_dbm_rom_path_tool.cpp deleted file mode 100644 index 6d4e6e1..0000000 --- a/libraries/libstratosphere/source/fssystem/fssystem_dbm_rom_path_tool.cpp +++ /dev/null @@ -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 . - */ -#include - -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(); - } - -} diff --git a/libraries/libstratosphere/source/fssystem/fssystem_romfs_filesystem.cpp b/libraries/libstratosphere/source/fssystem/fssystem_romfs_filesystem.cpp index 009c51d..d736962 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_romfs_filesystem.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_romfs_filesystem.cpp @@ -19,7 +19,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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(header.directory_bucket_size), - this->dir_entry_storage.get(), 0, static_cast(header.directory_entry_size), - this->file_bucket_storage.get(), 0, static_cast(header.file_bucket_size), - this->file_entry_storage.get(), 0, static_cast(header.file_entry_size))); + R_TRY(this->rom_file_table.Initialize(fs::SubStorage(this->dir_bucket_storage.get(), 0, static_cast(header.directory_bucket_size)), + fs::SubStorage(this->dir_entry_storage.get(), 0, static_cast(header.directory_entry_size)), + fs::SubStorage(this->file_bucket_storage.get(), 0, static_cast(header.file_bucket_size)), + fs::SubStorage(this->file_entry_storage.get(), 0, static_cast(header.file_entry_size)))); /* Set members. */ this->entry_size = header.body_offset; @@ -326,7 +326,7 @@ 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())