| // Copyright 2021 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/fdio/namespace.h> |
| |
| #include "src/storage/fs_test/fs_test.h" |
| #include "src/storage/lib/fs_management/cpp/mount.h" |
| #include "src/storage/memfs/memfs.h" |
| #include "src/storage/memfs/vnode_dir.h" |
| |
| namespace { |
| |
| class MemfsInstance : public fs_test::FilesystemInstance { |
| public: |
| MemfsInstance() : loop_(&kAsyncLoopConfigNeverAttachToThread) {} |
| ~MemfsInstance() override { Shutdown(); } |
| |
| zx::result<> Format(const fs_test::TestFilesystemOptions&) override { |
| Shutdown(); |
| |
| zx::result result = memfs::Memfs::Create(loop_.dispatcher(), "<tmp>"); |
| if (result.is_error()) { |
| return result.take_error(); |
| } |
| auto& [memfs, root] = result.value(); |
| |
| zx::result server = fidl::CreateEndpoints(&root_); |
| if (server.is_error()) { |
| return server.take_error(); |
| } |
| |
| if (zx_status_t status = memfs->ServeDirectory(std::move(root), std::move(server.value())); |
| status != ZX_OK) { |
| return zx::error(status); |
| } |
| if (zx_status_t status = loop_.StartThread(); status != ZX_OK) { |
| return zx::error(status); |
| } |
| memfs_ = std::move(memfs); |
| return zx::ok(); |
| } |
| |
| zx::result<> Mount(const std::string& mount_path, |
| const fs_management::MountOptions& options) override { |
| if (!root_) { |
| // Already mounted. |
| return zx::error(ZX_ERR_BAD_STATE); |
| } |
| |
| fdio_ns_t* ns; |
| if (auto status = zx::make_result(fdio_ns_get_installed(&ns)); status.is_error()) { |
| return status; |
| } |
| return zx::make_result(fdio_ns_bind(ns, fs_test::StripTrailingSlash(mount_path).c_str(), |
| root_.TakeChannel().release())); |
| } |
| |
| zx::result<> Unmount(const std::string& mount_path) override { |
| return fs_test::FsUnbind(mount_path); |
| } |
| |
| zx::result<> Fsck() override { return zx::ok(); } |
| |
| zx::result<std::string> DevicePath() const override { return zx::error(ZX_ERR_BAD_STATE); } |
| |
| fs_management::SingleVolumeFilesystemInterface* fs() override { return nullptr; } |
| |
| std::string GetMoniker() const override { |
| ZX_ASSERT_MSG(false, "GetMoniker unimplemented for MemfsInstance"); |
| return ""; |
| } |
| |
| private: |
| void Shutdown() { |
| loop_.Quit(); |
| loop_.JoinThreads(); |
| zx_status_t status = loop_.ResetQuit(); |
| ZX_ASSERT_MSG(status == ZX_OK, "%s", zx_status_get_string(status)); |
| } |
| |
| fidl::ClientEnd<fuchsia_io::Directory> root_; |
| std::unique_ptr<memfs::Memfs> memfs_; |
| async::Loop loop_; |
| }; |
| |
| class MemfsFilesystem : public fs_test::FilesystemImpl<MemfsFilesystem> { |
| public: |
| zx::result<std::unique_ptr<fs_test::FilesystemInstance>> Make( |
| const fs_test::TestFilesystemOptions& options) const override { |
| auto instance = std::make_unique<MemfsInstance>(); |
| zx::result<> status = instance->Format(options); |
| if (status.is_error()) { |
| return status.take_error(); |
| } |
| return zx::ok(std::move(instance)); |
| } |
| const Traits& GetTraits() const override { |
| static Traits traits{ |
| .in_memory = true, |
| .is_case_sensitive = true, |
| .is_journaled = false, |
| .name = "memfs", |
| .supports_hard_links = true, |
| .supports_mmap = true, |
| .supports_mmap_shared_write = true, |
| .supports_resize = false, |
| .supports_sparse_files = true, |
| .supports_watch_event_deleted = false, |
| .timestamp_granularity = zx::nsec(1), |
| }; |
| return traits; |
| } |
| }; |
| |
| } // namespace |
| |
| __EXPORT std::unique_ptr<fs_test::Filesystem> GetFilesystem() { |
| return std::make_unique<MemfsFilesystem>(); |
| } |