From 32f6660b7a1166edf0ff114ad35961e058a91b3a Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 3 Mar 2020 21:52:28 -0800 Subject: [PATCH] fs: implement accessor wrappers for ncm --- .../include/stratosphere/fs.hpp | 2 + .../include/stratosphere/fs/fs_common.hpp | 6 - .../stratosphere/fs/fs_memory_management.hpp | 51 ++++ .../include/stratosphere/fs/fs_mount.hpp | 27 ++ .../stratosphere/fs/fs_remote_filesystem.hpp | 32 ++- .../stratosphere/fs/fs_remote_storage.hpp | 9 +- .../stratosphere/fs/fsa/fs_registrar.hpp | 35 +++ .../stratosphere/fs/impl/fs_newable.hpp | 40 +++ .../source/fs/fs_file_path_hash.hpp | 36 +++ .../source/fs/fs_memory_management.cpp | 83 ++++++ .../source/fs/fs_scoped_setter.hpp | 60 +++++ .../source/fs/fsa/fs_directory_accessor.cpp | 39 +++ .../source/fs/fsa/fs_directory_accessor.hpp | 38 +++ .../source/fs/fsa/fs_file_accessor.cpp | 123 +++++++++ .../source/fs/fsa/fs_file_accessor.hpp | 68 +++++ .../source/fs/fsa/fs_filesystem_accessor.cpp | 243 ++++++++++++++++++ .../source/fs/fsa/fs_filesystem_accessor.hpp | 94 +++++++ .../source/fs/fsa/fs_mount_name.hpp | 26 ++ .../source/fs/fsa/fs_mount_table.cpp | 75 ++++++ .../source/fs/fsa/fs_mount_table.hpp | 40 +++ .../source/fs/fsa/fs_registrar.cpp | 51 ++++ .../source/fs/fsa/fs_user_mount_table.cpp | 41 +++ .../source/fs/fsa/fs_user_mount_table.hpp | 27 ++ .../include/vapours/results/fs_results.hpp | 9 + .../vapours/util/util_intrusive_list.hpp | 4 +- .../source/fs_mitm/fsmitm_boot0storage.hpp | 3 +- 26 files changed, 1230 insertions(+), 32 deletions(-) create mode 100644 libraries/libstratosphere/include/stratosphere/fs/fs_memory_management.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fs/fs_mount.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fs/fsa/fs_registrar.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/fs/impl/fs_newable.hpp create mode 100644 libraries/libstratosphere/source/fs/fs_file_path_hash.hpp create mode 100644 libraries/libstratosphere/source/fs/fs_memory_management.cpp create mode 100644 libraries/libstratosphere/source/fs/fs_scoped_setter.hpp create mode 100644 libraries/libstratosphere/source/fs/fsa/fs_directory_accessor.cpp create mode 100644 libraries/libstratosphere/source/fs/fsa/fs_directory_accessor.hpp create mode 100644 libraries/libstratosphere/source/fs/fsa/fs_file_accessor.cpp create mode 100644 libraries/libstratosphere/source/fs/fsa/fs_file_accessor.hpp create mode 100644 libraries/libstratosphere/source/fs/fsa/fs_filesystem_accessor.cpp create mode 100644 libraries/libstratosphere/source/fs/fsa/fs_filesystem_accessor.hpp create mode 100644 libraries/libstratosphere/source/fs/fsa/fs_mount_name.hpp create mode 100644 libraries/libstratosphere/source/fs/fsa/fs_mount_table.cpp create mode 100644 libraries/libstratosphere/source/fs/fsa/fs_mount_table.hpp create mode 100644 libraries/libstratosphere/source/fs/fsa/fs_registrar.cpp create mode 100644 libraries/libstratosphere/source/fs/fsa/fs_user_mount_table.cpp create mode 100644 libraries/libstratosphere/source/fs/fsa/fs_user_mount_table.hpp diff --git a/libraries/libstratosphere/include/stratosphere/fs.hpp b/libraries/libstratosphere/include/stratosphere/fs.hpp index 60e62d90e..1daffe930 100644 --- a/libraries/libstratosphere/include/stratosphere/fs.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs.hpp @@ -19,10 +19,12 @@ #include "fs/fsa/fs_ifile.hpp" #include "fs/fsa/fs_idirectory.hpp" #include "fs/fsa/fs_ifilesystem.hpp" +#include "fs/fsa/fs_registrar.hpp" #include "fs/fs_remote_filesystem.hpp" #include "fs/fs_istorage.hpp" #include "fs/fs_remote_storage.hpp" #include "fs/fs_file_storage.hpp" #include "fs/fs_query_range.hpp" +#include "fs/fs_mount.hpp" #include "fs/fs_path_tool.hpp" #include "fs/fs_path_utils.hpp" diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_common.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_common.hpp index 13b0d5a14..5a50e5704 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_common.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_common.hpp @@ -19,9 +19,3 @@ #include "../ncm.hpp" #include "../sf.hpp" -namespace ams::fs { - - /* TODO: Better place for this? */ - constexpr inline size_t MountNameLengthMax = 15; - -} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_memory_management.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_memory_management.hpp new file mode 100644 index 000000000..cc9a31a2f --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_memory_management.hpp @@ -0,0 +1,51 @@ +/* + * 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 AllocateFunction = void *(*)(size_t); + using DeallocateFunction = void (*)(void *, size_t); + + void SetAllocator(AllocateFunction allocator, DeallocateFunction deallocator); + + namespace impl { + + void *Allocate(size_t size); + void Deallocate(void *ptr, size_t size); + + class Deleter { + private: + size_t size; + public: + Deleter() : size() { /* ... */ } + explicit Deleter(size_t sz) : size(sz) { /* ... */ } + + void operator()(void *ptr) const { + ::ams::fs::impl::Deallocate(ptr, this->size); + } + }; + + template + std::unique_ptr MakeUnique() { + static_assert(std::is_pod::value); + return std::unique_ptr(static_cast(::ams::fs::impl::Allocate(sizeof(T))), Deleter(sizeof(T))); + } + + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_mount.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_mount.hpp new file mode 100644 index 000000000..1344b2a4d --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_mount.hpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include "fs_common.hpp" + +namespace ams::fs { + + constexpr inline size_t MountNameLengthMax = 15; + + Result ConvertToFsCommonPath(char *dst, size_t dst_size, const char *src); + + void Unmount(const char *mount_name); + +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp index 08c38988b..f12a02a4b 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_remote_filesystem.hpp @@ -15,20 +15,20 @@ */ #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" namespace ams::fs { - class RemoteFile : public fsa::IFile { + class RemoteFile : public fsa::IFile, public impl::Newable { private: - std::unique_ptr<::FsFile> base_file; + std::unique_ptr<::FsFile, impl::Deleter> base_file; public: - RemoteFile(::FsFile *f) : base_file(f) { /* ... */ } - RemoteFile(std::unique_ptr<::FsFile> f) : base_file(std::move(f)) { /* ... */ } - RemoteFile(::FsFile f) { - this->base_file = std::make_unique<::FsFile>(f); + RemoteFile(::FsFile &f) { + this->base_file = impl::MakeUnique<::FsFile>(); + *this->base_file = f; } virtual ~RemoteFile() { fsFileClose(this->base_file.get()); } @@ -63,14 +63,13 @@ namespace ams::fs { } }; - class RemoteDirectory : public fsa::IDirectory { + class RemoteDirectory : public fsa::IDirectory, public impl::Newable { private: - std::unique_ptr<::FsDir> base_dir; + std::unique_ptr<::FsDir, impl::Deleter> base_dir; public: - RemoteDirectory(::FsDir *d) : base_dir(d) { /* ... */ } - RemoteDirectory(std::unique_ptr<::FsDir> d) : base_dir(std::move(d)) { /* ... */ } - RemoteDirectory(::FsDir d) { - this->base_dir = std::make_unique<::FsDir>(d); + RemoteDirectory(::FsDir &d) { + this->base_dir = impl::MakeUnique<::FsDir>(); + *this->base_dir = d; } virtual ~RemoteDirectory() { fsDirClose(this->base_dir.get()); } @@ -90,12 +89,11 @@ namespace ams::fs { class RemoteFileSystem : public fsa::IFileSystem { private: - std::unique_ptr<::FsFileSystem> base_fs; + std::unique_ptr<::FsFileSystem, impl::Deleter> base_fs; public: - RemoteFileSystem(::FsFileSystem *fs) : base_fs(fs) { /* ... */ } - RemoteFileSystem(std::unique_ptr<::FsFileSystem> fs) : base_fs(std::move(fs)) { /* ... */ } - RemoteFileSystem(::FsFileSystem fs) { - this->base_fs = std::make_unique<::FsFileSystem>(fs); + RemoteFileSystem(::FsFileSystem &fs) { + this->base_fs = impl::MakeUnique<::FsFileSystem>(); + *this->base_fs = fs; } virtual ~RemoteFileSystem() { fsFsClose(this->base_fs.get()); } diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_remote_storage.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_remote_storage.hpp index d90e52fe1..ef195d2f7 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_remote_storage.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_remote_storage.hpp @@ -21,12 +21,11 @@ namespace ams::fs { class RemoteStorage : public IStorage { private: - std::unique_ptr<::FsStorage> base_storage; + std::unique_ptr<::FsStorage, impl::Deleter> base_storage; public: - RemoteStorage(::FsStorage *s) : base_storage(s) { /* ... */ } - RemoteStorage(std::unique_ptr<::FsStorage> s) : base_storage(std::move(s)) { /* ... */ } - RemoteStorage(::FsStorage s) { - this->base_storage = std::make_unique<::FsStorage>(s); + RemoteStorage(::FsStorage &s) { + this->base_storage = impl::MakeUnique<::FsStorage>(); + *this->base_storage = s; } virtual ~RemoteStorage() { fsStorageClose(this->base_storage.get()); } diff --git a/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_registrar.hpp b/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_registrar.hpp new file mode 100644 index 000000000..5135f0f22 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/fsa/fs_registrar.hpp @@ -0,0 +1,35 @@ +/* + * 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::fsa { + + class ICommonMountNameGenerator { + public: + virtual ~ICommonMountNameGenerator() { /* ... */ } + virtual Result GenerateCommonMountName(char *name, size_t name_size) = 0; + }; + + class IFileSystem; + + Result Register(const char *name, std::unique_ptr &&fs); + Result Register(const char *name, std::unique_ptr &&fs, std::unique_ptr &&generator); + /* TODO: Register with cache settings */ + + void Unregister(const char *name); +} diff --git a/libraries/libstratosphere/include/stratosphere/fs/impl/fs_newable.hpp b/libraries/libstratosphere/include/stratosphere/fs/impl/fs_newable.hpp new file mode 100644 index 000000000..7ceb7717f --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/fs/impl/fs_newable.hpp @@ -0,0 +1,40 @@ +/* + * 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::impl { + + class Newable { + public: + static void *operator new(size_t size) { + return ::ams::fs::impl::Allocate(size); + } + + static void *operator new[](size_t size) { + return ::ams::fs::impl::Allocate(size); + } + + static void operator delete(void *ptr, size_t size) { + return ::ams::fs::impl::Deallocate(ptr, size); + } + + static void operator delete[](void *ptr, size_t size) { + return ::ams::fs::impl::Deallocate(ptr, size); + } + }; + +} diff --git a/libraries/libstratosphere/source/fs/fs_file_path_hash.hpp b/libraries/libstratosphere/source/fs/fs_file_path_hash.hpp new file mode 100644 index 000000000..bbc580839 --- /dev/null +++ b/libraries/libstratosphere/source/fs/fs_file_path_hash.hpp @@ -0,0 +1,36 @@ +/* + * 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::impl { + + constexpr inline size_t FilePathHashSize = 4; + + struct FilePathHash : public Newable { + u8 data[FilePathHashSize]; + }; + static_assert(std::is_pod::value); + + inline bool operator==(const FilePathHash &lhs, const FilePathHash &rhs) { + return std::memcmp(lhs.data, rhs.data, FilePathHashSize) == 0; + } + + inline bool operator!=(const FilePathHash &lhs, const FilePathHash &rhs) { + return !(lhs == rhs); + } + +} diff --git a/libraries/libstratosphere/source/fs/fs_memory_management.cpp b/libraries/libstratosphere/source/fs/fs_memory_management.cpp new file mode 100644 index 000000000..ccf3f4396 --- /dev/null +++ b/libraries/libstratosphere/source/fs/fs_memory_management.cpp @@ -0,0 +1,83 @@ +/* + * 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 { + + namespace { + + bool g_used_default_allocator; + + void *DefaultAllocate(size_t size) { + g_used_default_allocator = true; + return std::malloc(size); + } + + void DefaultDeallocate(void *ptr, size_t size) { + std::free(ptr); + } + + os::Mutex g_lock; + AllocateFunction g_allocate_func = DefaultAllocate; + DeallocateFunction g_deallocate_func = DefaultDeallocate; + + constexpr size_t RequiredAlignment = alignof(u64); + + Result SetAllocatorImpl(AllocateFunction allocator, DeallocateFunction deallocator) { + /* Ensure SetAllocator is used correctly. */ + R_UNLESS(g_allocate_func == DefaultAllocate, fs::ResultAllocatorAlreadyRegistered()); + R_UNLESS(g_deallocate_func == DefaultDeallocate, fs::ResultAllocatorAlreadyRegistered()); + R_UNLESS(allocator != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(deallocator != nullptr, fs::ResultNullptrArgument()); + R_UNLESS(!g_used_default_allocator, fs::ResultDefaultAllocatorUsed()); + + /* Set allocators. */ + g_allocate_func = allocator; + g_deallocate_func = deallocator; + return ResultSuccess(); + } + + } + + void SetAllocator(AllocateFunction allocator, DeallocateFunction deallocator) { + R_ABORT_UNLESS(SetAllocatorImpl(allocator, deallocator)); + } + + namespace impl { + + void *Allocate(size_t size) { + void *ptr; + { + std::scoped_lock lk(g_lock); + ptr = g_allocate_func(size); + if (!util::IsAligned(reinterpret_cast(ptr), RequiredAlignment)) { + R_ABORT_UNLESS(fs::ResultAllocatorAlignmentViolation()); + } + } + return ptr; + } + + void Deallocate(void *ptr, size_t size) { + if (ptr == nullptr) { + return; + } + std::scoped_lock lk(g_lock); + g_deallocate_func(ptr, size); + } + + } + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/fs/fs_scoped_setter.hpp b/libraries/libstratosphere/source/fs/fs_scoped_setter.hpp new file mode 100644 index 000000000..d72dcbba3 --- /dev/null +++ b/libraries/libstratosphere/source/fs/fs_scoped_setter.hpp @@ -0,0 +1,60 @@ +/* + * 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 { + + template + class ScopedSetter { + NON_COPYABLE(ScopedSetter); + private: + T *ptr; + T value; + public: + constexpr ALWAYS_INLINE ScopedSetter(T &p, T v) : ptr(std::addressof(p)), value(v) { /* ... */ } + ALWAYS_INLINE ~ScopedSetter() { + if (this->ptr) { + *this->ptr = this->value; + } + } + + ALWAYS_INLINE ScopedSetter(ScopedSetter &&rhs) { + this->ptr = rhs.ptr; + this->value = rhs.value; + rhs.Reset(); + } + + ALWAYS_INLINE ScopedSetter &operator=(ScopedSetter &&rhs) { + this->ptr = rhs.ptr; + this->value = rhs.value; + rhs.Reset(); + return *this; + } + + ALWAYS_INLINE void Set(T v) { this->value = v; } + private: + ALWAYS_INLINE void Reset() { + this->ptr = nullptr; + } + }; + + template + ALWAYS_INLINE ScopedSetter MakeScopedSetter(T &p, T v) { + return ScopedSetter(p, v); + } + +} diff --git a/libraries/libstratosphere/source/fs/fsa/fs_directory_accessor.cpp b/libraries/libstratosphere/source/fs/fsa/fs_directory_accessor.cpp new file mode 100644 index 000000000..1cca9fcba --- /dev/null +++ b/libraries/libstratosphere/source/fs/fsa/fs_directory_accessor.cpp @@ -0,0 +1,39 @@ +/* + * 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 +#include "fs_directory_accessor.hpp" +#include "fs_filesystem_accessor.hpp" + +namespace ams::fs::impl { + + DirectoryAccessor::DirectoryAccessor(std::unique_ptr&& d, FileSystemAccessor &p) : impl(std::move(d)), parent(p) { + /* ... */ + } + + DirectoryAccessor::~DirectoryAccessor() { + this->impl.reset(); + this->parent.NotifyCloseDirectory(this); + } + + Result DirectoryAccessor::Read(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries) { + return this->impl->Read(out_count, out_entries, max_entries); + } + + Result DirectoryAccessor::GetEntryCount(s64 *out) { + return this->impl->GetEntryCount(out); + } + +} diff --git a/libraries/libstratosphere/source/fs/fsa/fs_directory_accessor.hpp b/libraries/libstratosphere/source/fs/fsa/fs_directory_accessor.hpp new file mode 100644 index 000000000..77bc44af5 --- /dev/null +++ b/libraries/libstratosphere/source/fs/fsa/fs_directory_accessor.hpp @@ -0,0 +1,38 @@ +/* + * 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::impl { + + class FileSystemAccessor; + + class DirectoryAccessor : public util::IntrusiveListBaseNode, public Newable { + NON_COPYABLE(DirectoryAccessor); + private: + std::unique_ptr impl; + FileSystemAccessor &parent; + public: + DirectoryAccessor(std::unique_ptr&& d, FileSystemAccessor &p); + ~DirectoryAccessor(); + + Result Read(s64 *out_count, DirectoryEntry *out_entries, s64 max_entries); + Result GetEntryCount(s64 *out); + + FileSystemAccessor &GetParent() const { return this->parent; } + }; + +} diff --git a/libraries/libstratosphere/source/fs/fsa/fs_file_accessor.cpp b/libraries/libstratosphere/source/fs/fsa/fs_file_accessor.cpp new file mode 100644 index 000000000..d620d2a53 --- /dev/null +++ b/libraries/libstratosphere/source/fs/fsa/fs_file_accessor.cpp @@ -0,0 +1,123 @@ +/* + * 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 +#include "../fs_scoped_setter.hpp" +#include "../fs_file_path_hash.hpp" +#include "fs_file_accessor.hpp" +#include "fs_filesystem_accessor.hpp" + +namespace ams::fs::impl { + + FileAccessor::FileAccessor(std::unique_ptr&& f, FileSystemAccessor *p, OpenMode mode) + : impl(std::move(f)), parent(p), write_state(WriteState::None), write_result(ResultSuccess()), open_mode(mode) + { + /* ... */ + } + + FileAccessor::~FileAccessor() { + /* Ensure that all files are flushed. */ + if (R_FAILED(this->write_result)) { + AMS_ABORT_UNLESS(this->write_state != WriteState::NeedsFlush); + } + this->impl.reset(); + + if (this->parent != nullptr) { + this->parent->NotifyCloseFile(this); + } + } + + Result FileAccessor::ReadWithCacheAccessLog(size_t *out, s64 offset, void *buf, size_t size, const ReadOption &option, bool use_path_cache, bool use_data_cache) { + AMS_ABORT(); + } + + Result FileAccessor::ReadWithoutCacheAccessLog(size_t *out, s64 offset, void *buf, size_t size, const ReadOption &option) { + return this->impl->Read(out, offset, buf, size, option); + } + + Result FileAccessor::Read(size_t *out, s64 offset, void *buf, size_t size, const ReadOption &option) { + /* Fail after a write fails. */ + R_TRY(this->write_result); + + /* TODO: Logging. */ + /* TODO: Support cache. */ + const bool use_path_cache = this->parent != nullptr && this->file_path_hash != nullptr; + const bool use_data_cache = /* TODO */false && this->parent != nullptr && this->parent->IsFileDataCacheAttachable(); + + if (use_path_cache && use_data_cache && false) { + /* TODO */ + return this->ReadWithCacheAccessLog(out, offset, buf, size, option, use_path_cache, use_data_cache); + } else { + return this->ReadWithoutCacheAccessLog(out, offset, buf, size, option); + } + } + + Result FileAccessor::Write(s64 offset, const void *buf, size_t size, const WriteOption &option) { + /* Fail after a write fails. */ + R_TRY(this->write_result); + + auto setter = MakeScopedSetter(this->write_state, WriteState::Failed); + if (this->file_path_hash != nullptr && /* TODO */ false) { + /* TODO */ + AMS_ABORT(); + } else { + R_TRY(this->UpdateLastResult(this->impl->Write(offset, buf, size, option))); + } + + setter.Set(option.HasFlushFlag() ? WriteState::None : WriteState::NeedsFlush); + + return ResultSuccess(); + } + + Result FileAccessor::Flush() { + /* Fail after a write fails. */ + R_TRY(this->write_result); + + auto setter = MakeScopedSetter(this->write_state, WriteState::Failed); + R_TRY(this->UpdateLastResult(this->impl->Flush())); + setter.Set(WriteState::None); + + return ResultSuccess(); + } + + Result FileAccessor::SetSize(s64 size) { + /* Fail after a write fails. */ + R_TRY(this->write_result); + + const WriteState old_write_state = this->write_state; + auto setter = MakeScopedSetter(this->write_state, WriteState::Failed); + + R_TRY(this->UpdateLastResult(this->impl->SetSize(size))); + + if (this->file_path_hash != nullptr) { + /* TODO: invalidate path cache */ + } + + setter.Set(old_write_state); + return ResultSuccess(); + } + + Result FileAccessor::GetSize(s64 *out) { + /* Fail after a write fails. */ + R_TRY(this->write_result); + + return this->impl->GetSize(out); + } + + Result FileAccessor::OperateRange(void *dst, size_t dst_size, OperationId operation, s64 offset, s64 size, const void *src, size_t src_size) { + return this->impl->OperateRange(dst, dst_size, operation, offset, size, src, src_size); + } + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/fs/fsa/fs_file_accessor.hpp b/libraries/libstratosphere/source/fs/fsa/fs_file_accessor.hpp new file mode 100644 index 000000000..ddb2ac2ab --- /dev/null +++ b/libraries/libstratosphere/source/fs/fsa/fs_file_accessor.hpp @@ -0,0 +1,68 @@ +/* + * 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::impl { + + struct FilePathHash; + class FileSystemAccessor; + + enum class WriteState { + None, + NeedsFlush, + Failed, + }; + + class FileAccessor : public util::IntrusiveListBaseNode, public Newable { + NON_COPYABLE(FileAccessor); + private: + std::unique_ptr impl; + FileSystemAccessor * const parent; + WriteState write_state; + Result write_result; + const OpenMode open_mode; + std::unique_ptr file_path_hash; + s32 path_hash_index; + public: + FileAccessor(std::unique_ptr&& f, FileSystemAccessor *p, OpenMode mode); + ~FileAccessor(); + + Result Read(size_t *out, s64 offset, void *buf, size_t size, const ReadOption &option); + Result Write(s64 offset, const void *buf, size_t size, const WriteOption &option); + Result Flush(); + Result SetSize(s64 size); + Result GetSize(s64 *out); + Result OperateRange(void *dst, size_t dst_size, OperationId operation, s64 offset, s64 size, const void *src, size_t src_size); + + OpenMode GetOpenMode() const { return this->open_mode; } + WriteState GetWriteState() const { return this->write_state; } + FileSystemAccessor *GetParent() const { return this->parent; } + + void SetFilePathHash(std::unique_ptr&& file_path_hash, s32 index); + Result ReadWithoutCacheAccessLog(size_t *out, s64 offset, void *buf, size_t size, const ReadOption &option); + private: + Result ReadWithCacheAccessLog(size_t *out, s64 offset, void *buf, size_t size, const ReadOption &option, bool use_path_cache, bool use_data_cache); + + ALWAYS_INLINE Result UpdateLastResult(Result r) { + if (!fs::ResultNotEnoughFreeSpace::Includes(r)) { + this->write_result = r; + } + return r; + } + }; + +} diff --git a/libraries/libstratosphere/source/fs/fsa/fs_filesystem_accessor.cpp b/libraries/libstratosphere/source/fs/fsa/fs_filesystem_accessor.cpp new file mode 100644 index 000000000..cdd17854b --- /dev/null +++ b/libraries/libstratosphere/source/fs/fsa/fs_filesystem_accessor.cpp @@ -0,0 +1,243 @@ +/* + * 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 +#include "fs_file_accessor.hpp" +#include "fs_directory_accessor.hpp" +#include "fs_filesystem_accessor.hpp" + +namespace ams::fs::impl { + + namespace { + + template + void Remove(List &list, Iter *desired) { + for (auto it = list.cbegin(); it != list.cend(); it++) { + if (it.operator->() == desired) { + list.erase(it); + return; + } + } + + /* This should never happen. */ + AMS_ABORT(); + } + + Result ValidatePath(const char *mount_name, const char *path) { + const size_t mount_name_len = strnlen(mount_name, MountNameLengthMax); + const size_t path_len = strnlen(path, EntryNameLengthMax); + R_UNLESS(mount_name_len + 1 + path_len <= EntryNameLengthMax, fs::ResultTooLongPath()); + + return ResultSuccess(); + } + + Result ValidateMountName(const char *name) { + R_UNLESS(name[0] != 0, fs::ResultInvalidMountName()); + R_UNLESS(strnlen(name, sizeof(MountName)) < sizeof(MountName), fs::ResultInvalidMountName()); + return ResultSuccess(); + } + + template + Result ValidateNoOpenWriteModeFiles(List &list) { + for (auto it = list.cbegin(); it != list.cend(); it++) { + R_UNLESS((it->GetOpenMode() & OpenMode_Write) == 0, fs::ResultWriteModeFileNotClosed()); + } + return ResultSuccess(); + } + + } + + FileSystemAccessor::FileSystemAccessor(const char *n, std::unique_ptr &&fs, std::unique_ptr &&generator) + : impl(std::move(fs)), mount_name_generator(std::move(generator)), + access_log_enabled(false), data_cache_attachable(false), path_cache_attachable(false), path_cache_attached(false), multi_commit_supported(false) + { + R_ABORT_UNLESS(ValidateMountName(n)); + std::strncpy(this->name.str, n, MountNameLengthMax); + this->name.str[MountNameLengthMax] = 0; + } + + FileSystemAccessor::~FileSystemAccessor() { + std::scoped_lock lk(this->open_list_lock); + + /* TODO: Iterate over list entries. */ + + if (!this->open_file_list.empty()) { R_ABORT_UNLESS(fs::ResultFileNotClosed()); } + if (!this->open_dir_list.empty()) { R_ABORT_UNLESS(fs::ResultDirectoryNotClosed()); } + + if (this->path_cache_attached) { + /* TODO: Invalidate path cache */ + } + } + + Result FileSystemAccessor::GetCommonMountName(char *dst, size_t dst_size) const { + R_UNLESS(this->mount_name_generator != nullptr, fs::ResultPreconditionViolation()); + return this->mount_name_generator->GenerateCommonMountName(dst, dst_size); + } + + std::shared_ptr FileSystemAccessor::GetMultiCommitTarget() { + if (this->multi_commit_supported) { + /* TODO: Support multi commit. */ + AMS_ABORT(); + } + return nullptr; + } + + void FileSystemAccessor::NotifyCloseFile(FileAccessor *f) { + std::scoped_lock lk(this->open_list_lock); + Remove(this->open_file_list, f); + } + + void FileSystemAccessor::NotifyCloseDirectory(DirectoryAccessor *d) { + std::scoped_lock lk(this->open_list_lock); + Remove(this->open_dir_list, d); + } + + Result FileSystemAccessor::CreateFile(const char *path, s64 size, int option) { + R_TRY(ValidatePath(this->name.str, path)); + if (this->path_cache_attached) { + /* TODO: Path cache */ + R_TRY(this->impl->CreateFile(path, size, option)); + } else { + R_TRY(this->impl->CreateFile(path, size, option)); + } + return ResultSuccess(); + } + + Result FileSystemAccessor::DeleteFile(const char *path) { + R_TRY(ValidatePath(this->name.str, path)); + return this->impl->DeleteFile(path); + } + + Result FileSystemAccessor::CreateDirectory(const char *path) { + R_TRY(ValidatePath(this->name.str, path)); + return this->impl->CreateDirectory(path); + } + + Result FileSystemAccessor::DeleteDirectory(const char *path) { + R_TRY(ValidatePath(this->name.str, path)); + return this->impl->DeleteDirectory(path); + } + + Result FileSystemAccessor::DeleteDirectoryRecursively(const char *path) { + R_TRY(ValidatePath(this->name.str, path)); + return this->impl->DeleteDirectoryRecursively(path); + } + + Result FileSystemAccessor::RenameFile(const char *old_path, const char *new_path) { + R_TRY(ValidatePath(this->name.str, old_path)); + R_TRY(ValidatePath(this->name.str, new_path)); + if (this->path_cache_attached) { + /* TODO: Path cache */ + R_TRY(this->impl->RenameFile(old_path, new_path)); + } else { + R_TRY(this->impl->RenameFile(old_path, new_path)); + } + return ResultSuccess(); + } + + Result FileSystemAccessor::RenameDirectory(const char *old_path, const char *new_path) { + R_TRY(ValidatePath(this->name.str, old_path)); + R_TRY(ValidatePath(this->name.str, new_path)); + if (this->path_cache_attached) { + /* TODO: Path cache */ + R_TRY(this->impl->RenameDirectory(old_path, new_path)); + } else { + R_TRY(this->impl->RenameDirectory(old_path, new_path)); + } + return ResultSuccess(); + } + + Result FileSystemAccessor::GetEntryType(DirectoryEntryType *out, const char *path) { + R_TRY(ValidatePath(this->name.str, path)); + return this->impl->GetEntryType(out, path); + } + + Result FileSystemAccessor::OpenFile(std::unique_ptr *out_file, const char *path, OpenMode mode) { + R_TRY(ValidatePath(this->name.str, path)); + + std::unique_ptr file; + R_TRY(this->impl->OpenFile(std::addressof(file), path, mode)); + + auto accessor = new FileAccessor(std::move(file), this, mode); + R_UNLESS(accessor != nullptr, fs::ResultAllocationFailureInFileSystemAccessorA()); + + { + std::scoped_lock lk(this->open_list_lock); + this->open_file_list.push_back(*accessor); + } + + if (this->path_cache_attached) { + if (mode & OpenMode_Append) { + /* TODO: Append Path cache */ + } else { + /* TODO: Non-append path cache */ + } + } + + out_file->reset(accessor); + return ResultSuccess(); + } + + Result FileSystemAccessor::OpenDirectory(std::unique_ptr *out_dir, const char *path, OpenDirectoryMode mode) { + R_TRY(ValidatePath(this->name.str, path)); + + std::unique_ptr dir; + R_TRY(this->impl->OpenDirectory(std::addressof(dir), path, mode)); + + auto accessor = new DirectoryAccessor(std::move(dir), *this); + R_UNLESS(accessor != nullptr, fs::ResultAllocationFailureInFileSystemAccessorB()); + + { + std::scoped_lock lk(this->open_list_lock); + this->open_dir_list.push_back(*accessor); + } + + out_dir->reset(accessor); + return ResultSuccess(); + } + + Result FileSystemAccessor::Commit() { + { + std::scoped_lock lk(this->open_list_lock); + R_ABORT_UNLESS(ValidateNoOpenWriteModeFiles(this->open_file_list)); + } + return this->impl->Commit(); + } + + Result FileSystemAccessor::GetFreeSpaceSize(s64 *out, const char *path) { + R_TRY(ValidatePath(this->name.str, path)); + return this->impl->GetFreeSpaceSize(out, path); + } + + Result FileSystemAccessor::GetTotalSpaceSize(s64 *out, const char *path) { + R_TRY(ValidatePath(this->name.str, path)); + return this->impl->GetTotalSpaceSize(out, path); + } + + Result FileSystemAccessor::CleanDirectoryRecursively(const char *path) { + R_TRY(ValidatePath(this->name.str, path)); + return this->impl->CleanDirectoryRecursively(path); + } + + Result FileSystemAccessor::GetFileTimeStampRaw(FileTimeStampRaw *out, const char *path) { + return this->impl->GetFileTimeStampRaw(out, path); + } + + Result FileSystemAccessor::QueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fsa::QueryId query, const char *path) { + return this->impl->QueryEntry(dst, dst_size, src, src_size, query, path); + } + + +} diff --git a/libraries/libstratosphere/source/fs/fsa/fs_filesystem_accessor.hpp b/libraries/libstratosphere/source/fs/fsa/fs_filesystem_accessor.hpp new file mode 100644 index 000000000..958d8cd78 --- /dev/null +++ b/libraries/libstratosphere/source/fs/fsa/fs_filesystem_accessor.hpp @@ -0,0 +1,94 @@ +/* + * 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 "fs_mount_name.hpp" + +namespace ams::fs::impl { + + class FileAccessor; + class DirectoryAccessor; + + class FileSystemAccessor : public util::IntrusiveListBaseNode, public Newable { + NON_COPYABLE(FileSystemAccessor); + friend class FileAccessor; + friend class DirectoryAccessor; + private: + using FileList = util::IntrusiveListBaseTraits::ListType; + using DirList = util::IntrusiveListBaseTraits::ListType; + private: + MountName name; + std::unique_ptr impl; + FileList open_file_list; + DirList open_dir_list; + os::Mutex open_list_lock; + std::unique_ptr mount_name_generator; + bool access_log_enabled; + bool data_cache_attachable; + bool path_cache_attachable; + bool path_cache_attached; + bool multi_commit_supported; + public: + FileSystemAccessor(const char *name, std::unique_ptr &&fs, std::unique_ptr &&generator = nullptr); + virtual ~FileSystemAccessor(); + + Result CreateFile(const char *path, s64 size, int option); + Result DeleteFile(const char *path); + Result CreateDirectory(const char *path); + Result DeleteDirectory(const char *path); + Result DeleteDirectoryRecursively(const char *path); + Result RenameFile(const char *old_path, const char *new_path); + Result RenameDirectory(const char *old_path, const char *new_path); + Result GetEntryType(DirectoryEntryType *out, const char *path); + Result OpenFile(std::unique_ptr *out_file, const char *path, OpenMode mode); + Result OpenDirectory(std::unique_ptr *out_dir, const char *path, OpenDirectoryMode mode); + Result Commit(); + Result GetFreeSpaceSize(s64 *out, const char *path); + Result GetTotalSpaceSize(s64 *out, const char *path); + Result CleanDirectoryRecursively(const char *path); + Result GetFileTimeStampRaw(FileTimeStampRaw *out, const char *path); + Result QueryEntry(char *dst, size_t dst_size, const char *src, size_t src_size, fsa::QueryId query, const char *path); + + const char *GetName() const { return this->name.str; } + Result GetCommonMountName(char *dst, size_t dst_size) const; + + void SetAccessLogEnabled(bool en) { this->access_log_enabled = en; } + void SetFileDataCacheAttachable(bool en) { this->data_cache_attachable = en; } + void SetPathBasedFileDataCacheAttachable(bool en) { this->path_cache_attachable = en; } + void SetMultiCommitSupported(bool en) { this->multi_commit_supported = en; } + + bool IsAccessLogEnabled() const { return this->access_log_enabled; } + bool IsFileDataCacheAttachable() const { return this->data_cache_attachable; } + bool IsPathBasedFileDataCacheAttachable() const { return this->path_cache_attachable; } + + void AttachPathBasedFileDataCache() { + if (this->IsPathBasedFileDataCacheAttachable()) { + this->path_cache_attached = true; + } + } + + void DetachPathBasedFileDataCache() { + this->path_cache_attached = false; + } + + std::shared_ptr GetMultiCommitTarget(); + private: + void NotifyCloseFile(FileAccessor *f); + void NotifyCloseDirectory(DirectoryAccessor *d); + }; + +} diff --git a/libraries/libstratosphere/source/fs/fsa/fs_mount_name.hpp b/libraries/libstratosphere/source/fs/fsa/fs_mount_name.hpp new file mode 100644 index 000000000..8f77d3fe2 --- /dev/null +++ b/libraries/libstratosphere/source/fs/fsa/fs_mount_name.hpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::fs { + + struct MountName { + char str[MountNameLengthMax + 1]; + }; + static_assert(std::is_pod::value); + +} diff --git a/libraries/libstratosphere/source/fs/fsa/fs_mount_table.cpp b/libraries/libstratosphere/source/fs/fsa/fs_mount_table.cpp new file mode 100644 index 000000000..fde663d26 --- /dev/null +++ b/libraries/libstratosphere/source/fs/fsa/fs_mount_table.cpp @@ -0,0 +1,75 @@ +/* + * 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 +#include "fs_mount_table.hpp" + +namespace ams::fs::impl { + + namespace { + + bool MatchesName(const FileSystemAccessor &accessor, const char *name) { + return std::strncmp(accessor.GetName(), name, sizeof(MountName)) == 0; + } + + } + + bool MountTable::CanAcceptMountName(const char *name) { + for (const auto &fs : this->fs_list) { + if (MatchesName(fs, name)) { + return false; + } + } + return true; + } + + Result MountTable::Mount(std::unique_ptr &&fs) { + std::scoped_lock lk(this->mutex); + + R_UNLESS(this->CanAcceptMountName(fs->GetName()), fs::ResultMountNameAlreadyExists()); + + this->fs_list.push_back(*fs.release()); + return ResultSuccess(); + } + + Result MountTable::Find(FileSystemAccessor **out, const char *name) { + std::scoped_lock lk(this->mutex); + + for (auto &fs : this->fs_list) { + if (MatchesName(fs, name)) { + *out = std::addressof(fs); + return ResultSuccess(); + } + } + + return fs::ResultNotMounted(); + } + + void MountTable::Unmount(const char *name) { + std::scoped_lock lk(this->mutex); + + for (auto it = this->fs_list.cbegin(); it != this->fs_list.cend(); it++) { + if (MatchesName(*it, name)) { + auto p = std::addressof(*it); + this->fs_list.erase(it); + delete p; + return; + } + } + + R_ABORT_UNLESS(fs::ResultNotMounted()); + } + +} diff --git a/libraries/libstratosphere/source/fs/fsa/fs_mount_table.hpp b/libraries/libstratosphere/source/fs/fsa/fs_mount_table.hpp new file mode 100644 index 000000000..2feac310e --- /dev/null +++ b/libraries/libstratosphere/source/fs/fsa/fs_mount_table.hpp @@ -0,0 +1,40 @@ +/* + * 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 "fs_filesystem_accessor.hpp" + +namespace ams::fs::impl { + + class MountTable : public Newable { + NON_COPYABLE(MountTable); + NON_MOVEABLE(MountTable); + private: + using FileSystemList = util::IntrusiveListBaseTraits::ListType; + private: + FileSystemList fs_list; + os::Mutex mutex; + public: + MountTable() : fs_list(), mutex() { /* ... */ } + private: + bool CanAcceptMountName(const char *name); + public: + Result Mount(std::unique_ptr &&fs); + Result Find(FileSystemAccessor **out, const char *name); + void Unmount(const char *name); + }; + +} diff --git a/libraries/libstratosphere/source/fs/fsa/fs_registrar.cpp b/libraries/libstratosphere/source/fs/fsa/fs_registrar.cpp new file mode 100644 index 000000000..43c4d843a --- /dev/null +++ b/libraries/libstratosphere/source/fs/fsa/fs_registrar.cpp @@ -0,0 +1,51 @@ +/* + * 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 +#include "fs_filesystem_accessor.hpp" +#include "fs_user_mount_table.hpp" + +namespace ams::fs::fsa { + + Result Register(const char *name, std::unique_ptr &&fs) { + std::unique_ptr accessor(new impl::FileSystemAccessor(name, std::move(fs))); + R_UNLESS(accessor != nullptr, fs::ResultAllocationFailureInRegisterA()); + + return impl::Register(std::move(accessor)); + } + + Result Register(const char *name, std::unique_ptr &&fs, std::unique_ptr &&generator) { + std::unique_ptr accessor(new impl::FileSystemAccessor(name, std::move(fs), std::move(generator))); + R_UNLESS(accessor != nullptr, fs::ResultAllocationFailureInRegisterB()); + + return impl::Register(std::move(accessor)); + } + + Result Register(const char *name, std::unique_ptr &&fs, std::unique_ptr &&generator, bool use_data_cache, bool use_path_cache, bool support_multi_commit) { + std::unique_ptr accessor(new impl::FileSystemAccessor(name, std::move(fs), std::move(generator))); + R_UNLESS(accessor != nullptr, fs::ResultAllocationFailureInRegisterB()); + + accessor->SetFileDataCacheAttachable(use_data_cache); + accessor->SetPathBasedFileDataCacheAttachable(use_path_cache); + accessor->SetMultiCommitSupported(support_multi_commit); + + return impl::Register(std::move(accessor)); + } + + void Unregister(const char *name) { + impl::Unregister(name); + } + +} diff --git a/libraries/libstratosphere/source/fs/fsa/fs_user_mount_table.cpp b/libraries/libstratosphere/source/fs/fsa/fs_user_mount_table.cpp new file mode 100644 index 000000000..b9c50b45b --- /dev/null +++ b/libraries/libstratosphere/source/fs/fsa/fs_user_mount_table.cpp @@ -0,0 +1,41 @@ +/* + * 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 +#include "fs_user_mount_table.hpp" +#include "fs_mount_table.hpp" +#include "fs_filesystem_accessor.hpp" + +namespace ams::fs::impl { + + namespace { + + MountTable g_mount_table; + + } + + Result Register(std::unique_ptr &&fs) { + return g_mount_table.Mount(std::move(fs)); + } + + Result Find(FileSystemAccessor **out, const char *name) { + return g_mount_table.Find(out, name); + } + + void Unregister(const char *name) { + g_mount_table.Unmount(name); + } + +} diff --git a/libraries/libstratosphere/source/fs/fsa/fs_user_mount_table.hpp b/libraries/libstratosphere/source/fs/fsa/fs_user_mount_table.hpp new file mode 100644 index 000000000..456051599 --- /dev/null +++ b/libraries/libstratosphere/source/fs/fsa/fs_user_mount_table.hpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::fs::impl { + + class FileSystemAccessor; + + Result Register(std::unique_ptr &&fs); + Result Find(FileSystemAccessor **out, const char *name); + void Unregister(const char *name); + +} diff --git a/libraries/libvapours/include/vapours/results/fs_results.hpp b/libraries/libvapours/include/vapours/results/fs_results.hpp index a731c5041..aba056808 100644 --- a/libraries/libvapours/include/vapours/results/fs_results.hpp +++ b/libraries/libvapours/include/vapours/results/fs_results.hpp @@ -48,8 +48,12 @@ namespace ams::fs { R_DEFINE_ERROR_RESULT(OutOfRange, 3005); R_DEFINE_ERROR_RANGE(AllocationFailure, 3200, 3499); + R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemAccessorA, 3211); + R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemAccessorB, 3212); R_DEFINE_ERROR_RESULT(AllocationFailureInDirectorySaveDataFileSystem, 3321); R_DEFINE_ERROR_RESULT(AllocationFailureInSubDirectoryFileSystem, 3355); + R_DEFINE_ERROR_RESULT(AllocationFailureInRegisterA, 3365); + R_DEFINE_ERROR_RESULT(AllocationFailureInRegisterB, 3366); R_DEFINE_ERROR_RESULT(AllocationFailureInPathNormalizer, 3367); R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemInterfaceAdapter, 3407); @@ -107,7 +111,12 @@ namespace ams::fs { R_DEFINE_ERROR_RANGE(PermissionDenied, 6400, 6449); + R_DEFINE_ERROR_RESULT(NeedFlush, 6454); + R_DEFINE_ERROR_RESULT(FileNotClosed, 6455); + R_DEFINE_ERROR_RESULT(DirectoryNotClosed, 6456); R_DEFINE_ERROR_RESULT(WriteModeFileNotClosed, 6457); + R_DEFINE_ERROR_RESULT(AllocatorAlreadyRegistered, 6458); + R_DEFINE_ERROR_RESULT(DefaultAllocatorUsed, 6459); R_DEFINE_ERROR_RESULT(AllocatorAlignmentViolation, 6461); R_DEFINE_ERROR_RESULT(UserNotExist, 6465); diff --git a/libraries/libvapours/include/vapours/util/util_intrusive_list.hpp b/libraries/libvapours/include/vapours/util/util_intrusive_list.hpp index b19edb70f..511b289a7 100644 --- a/libraries/libvapours/include/vapours/util/util_intrusive_list.hpp +++ b/libraries/libvapours/include/vapours/util/util_intrusive_list.hpp @@ -276,7 +276,7 @@ namespace ams::util { splice_impl(pos, first, last); } - iterator erase(const iterator pos) { + iterator erase(const_iterator pos) { if (pos == this->end()) { return this->end(); } @@ -529,7 +529,7 @@ namespace ams::util { this->impl.splice(pos.GetImplIterator(), o.impl, first.GetImplIterator(), last.GetImplIterator()); } - iterator erase(const iterator pos) { + iterator erase(const_iterator pos) { return iterator(this->impl.erase(pos.GetImplIterator())); } diff --git a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_boot0storage.hpp b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_boot0storage.hpp index 0da76868d..a1ac52ed2 100644 --- a/stratosphere/ams_mitm/source/fs_mitm/fsmitm_boot0storage.hpp +++ b/stratosphere/ams_mitm/source/fs_mitm/fsmitm_boot0storage.hpp @@ -140,8 +140,7 @@ namespace ams::mitm::fs { private: bool CanModifyBctPublicKey(); public: - Boot0Storage(FsStorage *s, const sm::MitmProcessInfo &c) : Base(s), client_info(c) { /* ... */ } - Boot0Storage(FsStorage s, const sm::MitmProcessInfo &c) : Base(s), client_info(c) { /* ... */ } + Boot0Storage(FsStorage &s, const sm::MitmProcessInfo &c) : Base(s), client_info(c) { /* ... */ } public: virtual Result Read(s64 offset, void *_buffer, size_t size) override; virtual Result Write(s64 offset, const void *_buffer, size_t size) override;