| // Copyright 2017 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 <fuchsia/io/llcpp/fidl.h> |
| #include <lib/zx/vmo.h> |
| #include <limits.h> |
| #include <zircon/device/vfs.h> |
| #include <zircon/syscalls.h> |
| #include <zircon/syscalls/object.h> |
| |
| #include <zxtest/zxtest.h> |
| |
| #include "src/lib/storage/vfs/cpp/vfs_types.h" |
| #include "src/lib/storage/vfs/cpp/vmo_file.h" |
| |
| namespace { |
| |
| using VnodeOptions = fs::VnodeConnectionOptions; |
| using VnodeInfo = fs::VnodeRepresentation; |
| |
| const size_t VMO_SIZE = zx_system_get_page_size() * 3u; |
| const size_t PAGE_0 = 0u; |
| const size_t PAGE_1 = zx_system_get_page_size(); |
| const size_t PAGE_2 = zx_system_get_page_size() * 2u; |
| |
| zx_koid_t GetKoid(zx_handle_t handle) { |
| zx_info_handle_basic_t info; |
| zx_status_t status = |
| zx_object_get_info(handle, ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr, nullptr); |
| return status == ZX_OK ? info.koid : ZX_KOID_INVALID; |
| } |
| |
| zx_rights_t GetRights(zx_handle_t handle) { |
| zx_info_handle_basic_t info; |
| zx_status_t status = |
| zx_object_get_info(handle, ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr, nullptr); |
| return status == ZX_OK ? info.rights : 0u; |
| } |
| |
| void FillVmo(const zx::vmo& vmo, size_t offset, size_t length, uint8_t byte) { |
| uint8_t data[length]; |
| memset(data, byte, length); |
| |
| zx_status_t status = vmo.write(data, offset, length); |
| ASSERT_EQ(ZX_OK, status); |
| } |
| |
| void CheckVmo(const zx::vmo& vmo, size_t offset, size_t length, uint8_t expected_byte) { |
| uint8_t data[length]; |
| |
| zx_status_t status = vmo.read(data, offset, length); |
| ASSERT_EQ(ZX_OK, status); |
| |
| for (size_t i = 0; i < length; i++) { |
| ASSERT_EQ(expected_byte, data[i]); |
| } |
| } |
| |
| void CheckData(uint8_t* data, size_t offset, size_t length, uint8_t expected_byte) { |
| for (size_t i = 0; i < length; i++) { |
| ASSERT_EQ(expected_byte, data[i + offset]); |
| } |
| } |
| |
| void CreateVmoABC(zx::vmo* out_vmo) { |
| zx_status_t status = zx::vmo::create(VMO_SIZE, 0u, out_vmo); |
| ASSERT_EQ(ZX_OK, status); |
| |
| FillVmo(*out_vmo, PAGE_0, zx_system_get_page_size(), 'A'); |
| FillVmo(*out_vmo, PAGE_1, zx_system_get_page_size(), 'B'); |
| FillVmo(*out_vmo, PAGE_2, zx_system_get_page_size(), 'C'); |
| } |
| |
| TEST(VmoFile, Constructor) { |
| zx::vmo abc; |
| CreateVmoABC(&abc); |
| |
| // default parameters |
| { |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, 0u, zx_system_get_page_size()); |
| EXPECT_EQ(abc.get(), file->vmo_handle()); |
| EXPECT_EQ(0u, file->offset()); |
| EXPECT_EQ(zx_system_get_page_size(), file->length()); |
| EXPECT_FALSE(file->is_writable()); |
| EXPECT_EQ(fs::VmoFile::VmoSharing::DUPLICATE, file->vmo_sharing()); |
| } |
| |
| // everything explicit |
| { |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, 3u, PAGE_2 + 1u, true, |
| fs::VmoFile::VmoSharing::CLONE_COW); |
| EXPECT_EQ(abc.get(), file->vmo_handle()); |
| EXPECT_EQ(3u, file->offset()); |
| EXPECT_EQ(PAGE_2 + 1u, file->length()); |
| EXPECT_TRUE(file->is_writable()); |
| EXPECT_EQ(fs::VmoFile::VmoSharing::CLONE_COW, file->vmo_sharing()); |
| } |
| } |
| |
| #define EXPECT_RESULT_OK(expr) EXPECT_TRUE((expr).is_ok()) |
| #define EXPECT_RESULT_ERROR(error_val, expr) \ |
| EXPECT_TRUE((expr).is_error()); \ |
| EXPECT_EQ(error_val, (expr).error()) |
| |
| TEST(VmoFile, Open) { |
| zx::vmo abc; |
| CreateVmoABC(&abc); |
| |
| // read-only |
| { |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, 0u, 0u); |
| fbl::RefPtr<fs::Vnode> redirect; |
| auto result = file->ValidateOptions(VnodeOptions::ReadOnly()); |
| EXPECT_RESULT_OK(result); |
| EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect)); |
| EXPECT_NULL(redirect); |
| EXPECT_RESULT_ERROR(ZX_ERR_ACCESS_DENIED, file->ValidateOptions(VnodeOptions::ReadWrite())); |
| EXPECT_NULL(redirect); |
| EXPECT_RESULT_ERROR(ZX_ERR_ACCESS_DENIED, file->ValidateOptions(VnodeOptions::WriteOnly())); |
| EXPECT_NULL(redirect); |
| EXPECT_RESULT_ERROR(ZX_ERR_NOT_DIR, file->ValidateOptions(VnodeOptions().set_directory())); |
| EXPECT_NULL(redirect); |
| } |
| |
| // writable |
| { |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, 0u, 0u, true); |
| fbl::RefPtr<fs::Vnode> redirect; |
| auto result = file->ValidateOptions(VnodeOptions::ReadOnly()); |
| EXPECT_RESULT_OK(result); |
| EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect)); |
| EXPECT_NULL(redirect); |
| result = file->ValidateOptions(VnodeOptions::ReadWrite()); |
| EXPECT_RESULT_OK(result); |
| EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect)); |
| EXPECT_NULL(redirect); |
| result = file->ValidateOptions(VnodeOptions::WriteOnly()); |
| EXPECT_RESULT_OK(result); |
| EXPECT_EQ(ZX_OK, file->Open(result.value(), &redirect)); |
| EXPECT_NULL(redirect); |
| EXPECT_RESULT_ERROR(ZX_ERR_NOT_DIR, file->ValidateOptions(VnodeOptions().set_directory())); |
| EXPECT_NULL(redirect); |
| } |
| } |
| |
| TEST(VmoFile, Read) { |
| zx::vmo abc; |
| CreateVmoABC(&abc); |
| |
| uint8_t data[VMO_SIZE]; |
| memset(data, 0, VMO_SIZE); |
| |
| // empty read of non-empty file |
| { |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, 0u, zx_system_get_page_size()); |
| size_t actual = UINT64_MAX; |
| EXPECT_EQ(ZX_OK, file->Read(data, 0u, 0u, &actual)); |
| EXPECT_EQ(0u, actual); |
| } |
| |
| // non-empty read of empty file |
| { |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, 0u, 0u); |
| size_t actual = UINT64_MAX; |
| EXPECT_EQ(ZX_OK, file->Read(data, 1u, 0u, &actual)); |
| EXPECT_EQ(0u, actual); |
| } |
| |
| // empty read at end of file |
| { |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, 0u, 10u); |
| size_t actual = UINT64_MAX; |
| EXPECT_EQ(ZX_OK, file->Read(data, 0u, 10u, &actual)); |
| EXPECT_EQ(0u, actual); |
| } |
| |
| // non-empty read at end of file |
| { |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, 0u, 10u); |
| size_t actual = UINT64_MAX; |
| EXPECT_EQ(ZX_OK, file->Read(data, 1u, 10u, &actual)); |
| EXPECT_EQ(0u, actual); |
| } |
| |
| // empty read beyond end of file |
| { |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, 0u, 10u); |
| size_t actual = UINT64_MAX; |
| EXPECT_EQ(ZX_OK, file->Read(data, 0u, 11u, &actual)); |
| EXPECT_EQ(0u, actual); |
| } |
| |
| // non-empty read beyond end of file |
| { |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, 0u, 10u); |
| size_t actual = UINT64_MAX; |
| EXPECT_EQ(ZX_OK, file->Read(data, 1u, 11u, &actual)); |
| EXPECT_EQ(0u, actual); |
| } |
| |
| // short read of non-empty file |
| { |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, PAGE_1 - 3u, 10u); |
| size_t actual = UINT64_MAX; |
| EXPECT_EQ(ZX_OK, file->Read(data, 11u, 1u, &actual)); |
| EXPECT_EQ(9u, actual); |
| CheckData(data, 0u, 2u, 'A'); |
| CheckData(data, 2u, 7u, 'B'); |
| } |
| |
| // full read |
| { |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, 0u, VMO_SIZE); |
| size_t actual = UINT64_MAX; |
| EXPECT_EQ(ZX_OK, file->Read(data, VMO_SIZE, 0u, &actual)); |
| EXPECT_EQ(VMO_SIZE, actual); |
| CheckData(data, PAGE_0, zx_system_get_page_size(), 'A'); |
| CheckData(data, PAGE_1, zx_system_get_page_size(), 'B'); |
| CheckData(data, PAGE_2, zx_system_get_page_size(), 'C'); |
| } |
| } |
| |
| TEST(VmoFile, Write) { |
| zx::vmo abc; |
| CreateVmoABC(&abc); |
| |
| uint8_t data[VMO_SIZE]; |
| memset(data, '!', VMO_SIZE); |
| |
| // empty write of non-empty file |
| { |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, 0u, zx_system_get_page_size(), true); |
| size_t actual = UINT64_MAX; |
| EXPECT_EQ(ZX_OK, file->Write(data, 0u, 0u, &actual)); |
| EXPECT_EQ(0u, actual); |
| CheckVmo(abc, PAGE_0, zx_system_get_page_size(), 'A'); |
| CheckVmo(abc, PAGE_1, zx_system_get_page_size(), 'B'); |
| CheckVmo(abc, PAGE_2, zx_system_get_page_size(), 'C'); |
| } |
| |
| // non-empty write of empty file |
| { |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, 0u, 0u, true); |
| size_t actual = UINT64_MAX; |
| EXPECT_EQ(ZX_ERR_NO_SPACE, file->Write(data, 1u, 0u, &actual)); |
| } |
| |
| // empty write at end of file |
| { |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, 0u, 10u, true); |
| size_t actual = UINT64_MAX; |
| EXPECT_EQ(ZX_OK, file->Write(data, 0u, 10u, &actual)); |
| EXPECT_EQ(0u, actual); |
| CheckVmo(abc, PAGE_0, zx_system_get_page_size(), 'A'); |
| CheckVmo(abc, PAGE_1, zx_system_get_page_size(), 'B'); |
| CheckVmo(abc, PAGE_2, zx_system_get_page_size(), 'C'); |
| } |
| |
| // non-empty write at end of file |
| { |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, 0u, 10u, true); |
| size_t actual = UINT64_MAX; |
| EXPECT_EQ(ZX_ERR_NO_SPACE, file->Write(data, 1u, 10u, &actual)); |
| } |
| |
| // empty write beyond end of file |
| { |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, 0u, 10u, true); |
| size_t actual = UINT64_MAX; |
| EXPECT_EQ(ZX_OK, file->Write(data, 0u, 11u, &actual)); |
| EXPECT_EQ(0u, actual); |
| CheckVmo(abc, PAGE_0, zx_system_get_page_size(), 'A'); |
| CheckVmo(abc, PAGE_1, zx_system_get_page_size(), 'B'); |
| CheckVmo(abc, PAGE_2, zx_system_get_page_size(), 'C'); |
| } |
| |
| // non-empty write beyond end of file |
| { |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, 0u, 10u, true); |
| size_t actual = UINT64_MAX; |
| EXPECT_EQ(ZX_ERR_NO_SPACE, file->Write(data, 1u, 11u, &actual)); |
| } |
| |
| // short write of non-empty file |
| { |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, PAGE_1 - 3u, 10u, true); |
| size_t actual = UINT64_MAX; |
| EXPECT_EQ(ZX_OK, file->Write(data, 11u, 1u, &actual)); |
| EXPECT_EQ(9u, actual); |
| CheckVmo(abc, PAGE_0, zx_system_get_page_size() - 2u, 'A'); |
| CheckVmo(abc, PAGE_1 - 2u, 9u, '!'); |
| CheckVmo(abc, PAGE_1 + 7u, zx_system_get_page_size() - 7u, 'B'); |
| CheckVmo(abc, PAGE_2, zx_system_get_page_size(), 'C'); |
| } |
| |
| // full write |
| { |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, 0u, VMO_SIZE, true); |
| size_t actual = UINT64_MAX; |
| EXPECT_EQ(ZX_OK, file->Write(data, VMO_SIZE, 0u, &actual)); |
| EXPECT_EQ(VMO_SIZE, actual); |
| CheckVmo(abc, 0u, VMO_SIZE, '!'); |
| } |
| } |
| |
| TEST(VmoFile, Getattr) { |
| zx::vmo abc; |
| CreateVmoABC(&abc); |
| |
| // read-only |
| { |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, 0u, zx_system_get_page_size() * 3u + 117u); |
| fs::VnodeAttributes attr; |
| EXPECT_EQ(ZX_OK, file->GetAttributes(&attr)); |
| EXPECT_EQ(V_TYPE_FILE | V_IRUSR, attr.mode); |
| EXPECT_EQ(zx_system_get_page_size() * 3u + 117u, attr.content_size); |
| EXPECT_EQ(4u * zx_system_get_page_size(), attr.storage_size); |
| EXPECT_EQ(1u, attr.link_count); |
| } |
| |
| // writable |
| { |
| auto file = |
| fbl::MakeRefCounted<fs::VmoFile>(abc, 0u, zx_system_get_page_size() * 3u + 117u, true); |
| fs::VnodeAttributes attr; |
| EXPECT_EQ(ZX_OK, file->GetAttributes(&attr)); |
| EXPECT_EQ(V_TYPE_FILE | V_IRUSR | V_IWUSR, attr.mode); |
| EXPECT_EQ(zx_system_get_page_size() * 3u + 117u, attr.content_size); |
| EXPECT_EQ(4u * zx_system_get_page_size(), attr.storage_size); |
| EXPECT_EQ(1u, attr.link_count); |
| } |
| } |
| |
| TEST(VmoFile, GetNodeInfo) { |
| // sharing = VmoSharing::NONE |
| { |
| zx::vmo abc; |
| CreateVmoABC(&abc); |
| |
| fs::VnodeRepresentation info; |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, PAGE_1 - 5u, 23u, false, |
| fs::VmoFile::VmoSharing::NONE); |
| EXPECT_EQ(ZX_ERR_NOT_SUPPORTED, file->GetNodeInfo(fs::Rights::ReadOnly(), &info)); |
| } |
| |
| // sharing = VmoSharing::DUPLICATE, read only |
| { |
| zx::vmo abc; |
| CreateVmoABC(&abc); |
| |
| fs::VnodeRepresentation info; |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, PAGE_1 - 5u, 23u, false, |
| fs::VmoFile::VmoSharing::DUPLICATE); |
| EXPECT_EQ(ZX_OK, file->GetNodeInfo(fs::Rights::ReadOnly(), &info)); |
| ASSERT_TRUE(info.is_memory()); |
| VnodeInfo::Memory& memory = info.memory(); |
| zx::vmo vmo = std::move(memory.vmo); |
| EXPECT_NE(abc.get(), vmo.get()); |
| EXPECT_EQ(GetKoid(abc.get()), GetKoid(vmo.get())); |
| EXPECT_EQ(ZX_RIGHTS_BASIC | ZX_RIGHT_MAP | ZX_RIGHT_READ, GetRights(vmo.get())); |
| EXPECT_EQ(PAGE_1 - 5u, memory.offset); |
| EXPECT_EQ(23u, memory.length); |
| |
| CheckVmo(vmo, PAGE_1 - 5u, 5u, 'A'); |
| CheckVmo(vmo, PAGE_1, 18u, 'B'); |
| } |
| |
| // sharing = VmoSharing::DUPLICATE, read-write |
| { |
| zx::vmo abc; |
| CreateVmoABC(&abc); |
| |
| fs::VnodeRepresentation info; |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, PAGE_1 - 5u, 23u, true, |
| fs::VmoFile::VmoSharing::DUPLICATE); |
| EXPECT_EQ(ZX_OK, file->GetNodeInfo(fs::Rights::ReadWrite(), &info)); |
| ASSERT_TRUE(info.is_memory()); |
| VnodeInfo::Memory& memory = info.memory(); |
| zx::vmo vmo = std::move(memory.vmo); |
| EXPECT_NE(abc.get(), vmo.get()); |
| EXPECT_EQ(GetKoid(abc.get()), GetKoid(vmo.get())); |
| EXPECT_EQ(ZX_RIGHTS_BASIC | ZX_RIGHT_MAP | ZX_RIGHT_READ | ZX_RIGHT_WRITE, |
| GetRights(vmo.get())); |
| EXPECT_EQ(PAGE_1 - 5u, memory.offset); |
| EXPECT_EQ(23u, memory.length); |
| |
| CheckVmo(vmo, PAGE_1 - 5u, 5u, 'A'); |
| CheckVmo(vmo, PAGE_1, 18u, 'B'); |
| |
| FillVmo(vmo, PAGE_1 - 5u, 23u, '!'); |
| |
| CheckVmo(abc, 0u, zx_system_get_page_size() - 5u, 'A'); |
| CheckVmo(abc, PAGE_1 - 5u, 23u, '!'); |
| CheckVmo(abc, PAGE_1 + 18u, zx_system_get_page_size() - 18u, 'B'); |
| CheckVmo(abc, PAGE_2, zx_system_get_page_size(), 'C'); |
| } |
| |
| // sharing = VmoSharing::DUPLICATE, write only |
| { |
| zx::vmo abc; |
| CreateVmoABC(&abc); |
| |
| fs::VnodeRepresentation info; |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, PAGE_1 - 5u, 23u, true, |
| fs::VmoFile::VmoSharing::DUPLICATE); |
| EXPECT_EQ(ZX_OK, file->GetNodeInfo(fs::Rights::WriteOnly(), &info)); |
| ASSERT_TRUE(info.is_memory()); |
| VnodeInfo::Memory& memory = info.memory(); |
| zx::vmo vmo = std::move(memory.vmo); |
| EXPECT_NE(abc.get(), vmo.get()); |
| EXPECT_EQ(GetKoid(abc.get()), GetKoid(vmo.get())); |
| EXPECT_EQ(ZX_RIGHTS_BASIC | ZX_RIGHT_MAP | ZX_RIGHT_WRITE, GetRights(vmo.get())); |
| EXPECT_EQ(PAGE_1 - 5u, memory.offset); |
| EXPECT_EQ(23u, memory.length); |
| |
| FillVmo(vmo, PAGE_1 - 5u, 23u, '!'); |
| |
| CheckVmo(abc, 0u, zx_system_get_page_size() - 5u, 'A'); |
| CheckVmo(abc, PAGE_1 - 5u, 23u, '!'); |
| CheckVmo(abc, PAGE_1 + 18u, zx_system_get_page_size() - 18u, 'B'); |
| CheckVmo(abc, PAGE_2, zx_system_get_page_size(), 'C'); |
| } |
| |
| // sharing = VmoSharing::CLONE_COW, read only |
| { |
| zx::vmo abc; |
| CreateVmoABC(&abc); |
| |
| fs::VnodeRepresentation info; |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, PAGE_2 - 5u, 23u, false, |
| fs::VmoFile::VmoSharing::CLONE_COW); |
| // There is non-trivial lazy initialization happening here - repeat it |
| // to make sure it's nice and deterministic. |
| for (int i = 0; i < 2; i++) { |
| EXPECT_EQ(ZX_OK, file->GetNodeInfo(fs::Rights::ReadOnly(), &info)); |
| } |
| ASSERT_TRUE(info.is_memory()); |
| VnodeInfo::Memory& memory = info.memory(); |
| zx::vmo vmo = std::move(memory.vmo); |
| EXPECT_NE(abc.get(), vmo.get()); |
| EXPECT_NE(GetKoid(abc.get()), GetKoid(vmo.get())); |
| EXPECT_EQ(ZX_RIGHTS_BASIC | ZX_RIGHT_MAP | ZX_RIGHT_READ, GetRights(vmo.get())); |
| EXPECT_EQ(zx_system_get_page_size() - 5u, memory.offset); |
| EXPECT_EQ(23u, memory.length); |
| |
| CheckVmo(vmo, zx_system_get_page_size() - 5u, 5u, 'B'); |
| CheckVmo(vmo, zx_system_get_page_size(), 18u, 'C'); |
| } |
| |
| // sharing = VmoSharing::CLONE_COW, read-write |
| { |
| zx::vmo abc; |
| CreateVmoABC(&abc); |
| |
| fs::VnodeRepresentation info; |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, PAGE_2 - 5u, 23u, true, |
| fs::VmoFile::VmoSharing::CLONE_COW); |
| EXPECT_EQ(ZX_OK, file->GetNodeInfo(fs::Rights::ReadWrite(), &info)); |
| ASSERT_TRUE(info.is_memory()); |
| VnodeInfo::Memory& memory = info.memory(); |
| zx::vmo vmo = std::move(memory.vmo); |
| EXPECT_NE(abc.get(), vmo.get()); |
| EXPECT_NE(GetKoid(abc.get()), GetKoid(vmo.get())); |
| EXPECT_EQ(ZX_RIGHTS_BASIC | ZX_RIGHT_MAP | ZX_RIGHT_READ | ZX_RIGHT_WRITE, |
| GetRights(vmo.get())); |
| EXPECT_EQ(zx_system_get_page_size() - 5u, memory.offset); |
| EXPECT_EQ(23u, memory.length); |
| |
| CheckVmo(vmo, zx_system_get_page_size() - 5u, 5u, 'B'); |
| CheckVmo(vmo, zx_system_get_page_size(), 18u, 'C'); |
| |
| FillVmo(vmo, zx_system_get_page_size() - 5u, 23u, '!'); |
| |
| CheckVmo(abc, PAGE_0, zx_system_get_page_size(), 'A'); |
| CheckVmo(abc, PAGE_1, zx_system_get_page_size(), 'B'); |
| CheckVmo(abc, PAGE_2, zx_system_get_page_size(), 'C'); |
| } |
| |
| // sharing = VmoSharing::CLONE_COW, write only |
| { |
| zx::vmo abc; |
| CreateVmoABC(&abc); |
| |
| fs::VnodeRepresentation info; |
| auto file = fbl::MakeRefCounted<fs::VmoFile>(abc, PAGE_2 - 5u, 23u, true, |
| fs::VmoFile::VmoSharing::CLONE_COW); |
| EXPECT_EQ(ZX_OK, file->GetNodeInfo(fs::Rights::WriteOnly(), &info)); |
| ASSERT_TRUE(info.is_memory()); |
| VnodeInfo::Memory& memory = info.memory(); |
| zx::vmo vmo = std::move(memory.vmo); |
| EXPECT_NE(abc.get(), vmo.get()); |
| EXPECT_NE(GetKoid(abc.get()), GetKoid(vmo.get())); |
| EXPECT_EQ(ZX_RIGHTS_BASIC | ZX_RIGHT_MAP | ZX_RIGHT_WRITE, GetRights(vmo.get())); |
| EXPECT_EQ(zx_system_get_page_size() - 5u, memory.offset); |
| EXPECT_EQ(23u, memory.length); |
| |
| FillVmo(vmo, zx_system_get_page_size() - 5u, 23u, '!'); |
| |
| CheckVmo(abc, PAGE_0, zx_system_get_page_size(), 'A'); |
| CheckVmo(abc, PAGE_1, zx_system_get_page_size(), 'B'); |
| CheckVmo(abc, PAGE_2, zx_system_get_page_size(), 'C'); |
| } |
| } |
| |
| } // namespace |