| // Copyright 2018 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 <fcntl.h> |
| #include <unistd.h> |
| |
| #include <fbl/unique_fd.h> |
| #include <fuchsia/io/c/fidl.h> |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/fdio/fd.h> |
| #include <lib/memfs/memfs.h> |
| #include <lib/fzl/fdio.h> |
| #include <unittest/unittest.h> |
| |
| #include <utility> |
| |
| namespace { |
| |
| bool TryFilesystemOperations(const fzl::FdioCaller& caller) { |
| BEGIN_HELPER; |
| |
| const char* golden = "foobar"; |
| zx_status_t status; |
| uint64_t actual; |
| ASSERT_EQ(fuchsia_io_FileWriteAt(caller.borrow_channel(), |
| reinterpret_cast<const uint8_t*>(golden), |
| strlen(golden), 0, &status, &actual), |
| ZX_OK); |
| ASSERT_EQ(status, ZX_OK); |
| ASSERT_EQ(actual, strlen(golden)); |
| |
| char buf[256]; |
| ASSERT_EQ(fuchsia_io_FileReadAt(caller.borrow_channel(), static_cast<uint64_t>(sizeof(buf)), 0, |
| &status, reinterpret_cast<uint8_t*>(buf), sizeof(buf), &actual), |
| ZX_OK); |
| ASSERT_EQ(status, ZX_OK); |
| ASSERT_EQ(actual, strlen(golden)); |
| ASSERT_EQ(memcmp(buf, golden, strlen(golden)), 0); |
| |
| END_HELPER; |
| } |
| |
| class Harness { |
| public: |
| Harness() {} |
| |
| ~Harness() { |
| if (memfs_) { |
| sync_completion_t unmounted; |
| memfs_free_filesystem(memfs_, &unmounted); |
| sync_completion_wait(&unmounted, ZX_SEC(3)); |
| } |
| } |
| |
| bool Setup() { |
| BEGIN_HELPER; |
| ASSERT_EQ(loop_.StartThread(), ZX_OK); |
| zx_handle_t root; |
| ASSERT_EQ(memfs_create_filesystem(loop_.dispatcher(), &memfs_, &root), ZX_OK); |
| int fd; |
| ASSERT_EQ(fdio_fd_create(root, &fd), ZX_OK); |
| fbl::unique_fd dir(fd); |
| ASSERT_TRUE(dir); |
| fd_.reset(openat(dir.get(), "my-file", O_CREAT | O_RDWR)); |
| ASSERT_TRUE(fd_); |
| |
| END_HELPER; |
| } |
| |
| fbl::unique_fd fd() { return std::move(fd_); } |
| |
| private: |
| async::Loop loop_ = async::Loop(&kAsyncLoopConfigNoAttachToThread); |
| memfs_filesystem_t* memfs_ = nullptr; |
| fbl::unique_fd fd_; |
| }; |
| |
| bool FdioCallerFile() { |
| BEGIN_TEST; |
| |
| Harness harness; |
| ASSERT_TRUE(harness.Setup()); |
| auto fd = harness.fd(); |
| |
| // Try some filesystem operations. |
| fzl::FdioCaller caller(std::move(fd)); |
| ASSERT_TRUE(caller); |
| ASSERT_TRUE(TryFilesystemOperations(caller)); |
| |
| // Re-acquire the underlying fd. |
| fd = caller.release(); |
| ASSERT_EQ(close(fd.release()), 0); |
| |
| END_TEST; |
| } |
| |
| bool FdioCallerMoveAssignment() { |
| BEGIN_TEST; |
| |
| Harness harness; |
| ASSERT_TRUE(harness.Setup()); |
| auto fd = harness.fd(); |
| |
| fzl::FdioCaller caller(std::move(fd)); |
| fzl::FdioCaller move_assignment_caller = std::move(caller); |
| ASSERT_TRUE(move_assignment_caller); |
| ASSERT_FALSE(caller); |
| ASSERT_TRUE(TryFilesystemOperations(move_assignment_caller)); |
| |
| END_TEST; |
| } |
| |
| bool FdioCallerMoveConstructor() { |
| BEGIN_TEST; |
| |
| Harness harness; |
| ASSERT_TRUE(harness.Setup()); |
| auto fd = harness.fd(); |
| |
| fzl::FdioCaller caller(std::move(fd)); |
| fzl::FdioCaller move_ctor_caller(std::move(caller)); |
| ASSERT_TRUE(move_ctor_caller); |
| ASSERT_FALSE(caller); |
| ASSERT_TRUE(TryFilesystemOperations(move_ctor_caller)); |
| |
| END_TEST; |
| } |
| |
| } // namespace |
| |
| BEGIN_TEST_CASE(FdioCallTests) |
| RUN_TEST(FdioCallerFile) |
| RUN_TEST(FdioCallerMoveAssignment) |
| RUN_TEST(FdioCallerMoveConstructor) |
| END_TEST_CASE(FdioCallTests) |
| |