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;