| // Copyright 2019 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 "src/storage/lib/vfs/cpp/connection/node_connection.h" |
| |
| #include <fidl/fuchsia.io/cpp/common_types.h> |
| #include <fidl/fuchsia.io/cpp/natural_types.h> |
| #include <fidl/fuchsia.io/cpp/wire.h> |
| #include <lib/fidl/cpp/wire/channel.h> |
| #include <lib/fidl/cpp/wire/object_view.h> |
| #include <lib/fidl/cpp/wire/status.h> |
| #include <lib/fidl/cpp/wire/vector_view.h> |
| #include <lib/fit/function.h> |
| #include <lib/zx/channel.h> |
| #include <lib/zx/result.h> |
| #include <zircon/assert.h> |
| #include <zircon/availability.h> |
| #include <zircon/errors.h> |
| #include <zircon/types.h> |
| |
| #include <cstdint> |
| #include <optional> |
| #include <string_view> |
| #include <utility> |
| |
| #include <fbl/ref_ptr.h> |
| |
| #include "src/storage/lib/vfs/cpp/connection/connection.h" |
| #include "src/storage/lib/vfs/cpp/vfs_types.h" |
| #include "src/storage/lib/vfs/cpp/vnode.h" |
| |
| namespace fio = fuchsia_io; |
| |
| namespace fs::internal { |
| |
| NodeConnection::NodeConnection(fs::FuchsiaVfs* vfs, fbl::RefPtr<fs::Vnode> vnode, |
| fuchsia_io::Rights rights) |
| : Connection(vfs, std::move(vnode), rights) { |
| // Ensure the VFS does not create connections that have privileges which cannot be used. |
| ZX_DEBUG_ASSERT(internal::DownscopeRights(rights, VnodeProtocol::kNode) == rights); |
| } |
| |
| void NodeConnection::BindImpl(zx::channel channel, OnUnbound on_unbound) { |
| ZX_DEBUG_ASSERT(!binding_); |
| binding_.emplace(fidl::BindServer(vfs()->dispatcher(), |
| fidl::ServerEnd<fuchsia_io::Node>{std::move(channel)}, this, |
| [on_unbound = std::move(on_unbound)]( |
| NodeConnection* self, fidl::UnbindInfo, |
| fidl::ServerEnd<fuchsia_io::Node>) { on_unbound(self); })); |
| } |
| |
| void NodeConnection::Unbind() { |
| // NOTE: This needs to be thread-safe! |
| if (binding_) |
| binding_->Unbind(); |
| } |
| |
| #if FUCHSIA_API_LEVEL_LESS_THAN(NEXT) || FUCHSIA_API_LEVEL_AT_LEAST(PLATFORM) |
| void NodeConnection::DeprecatedClone(DeprecatedCloneRequestView request, |
| DeprecatedCloneCompleter::Sync& completer) { |
| fidl::ServerEnd<fio::Node> server_end{std::move(request->object)}; |
| if (request->flags & fio::wire::OpenFlags::kDescribe) { |
| // Ignore errors since there is nothing we can do if this fails. |
| [[maybe_unused]] auto result = |
| fidl::WireSendEvent(server_end)->OnOpen(ZX_ERR_NOT_SUPPORTED, {}); |
| } |
| server_end.Close(ZX_ERR_NOT_SUPPORTED); |
| } |
| #endif |
| |
| void NodeConnection::Clone(CloneRequestView request, CloneCompleter::Sync& completer) { |
| Connection::NodeClone(fio::Flags::kProtocolNode | fs::internal::RightsToFlags(rights()), |
| request->request.TakeChannel()); |
| } |
| |
| void NodeConnection::Close(CloseCompleter::Sync& completer) { |
| completer.Reply(zx::ok()); |
| Unbind(); |
| } |
| |
| void NodeConnection::Query(QueryCompleter::Sync& completer) { |
| const std::string_view kProtocolName = fidl::DiscoverableProtocolName<fio::Node>; |
| // TODO(https://fxbug.dev/42052765): avoid the const cast. |
| uint8_t* data = reinterpret_cast<uint8_t*>(const_cast<char*>(kProtocolName.data())); |
| completer.Reply(fidl::VectorView<uint8_t>::FromExternal(data, kProtocolName.size())); |
| } |
| |
| void NodeConnection::Sync(SyncCompleter::Sync& completer) { |
| completer.Reply(zx::make_result(ZX_ERR_BAD_HANDLE)); |
| } |
| |
| #if FUCHSIA_API_LEVEL_AT_LEAST(28) |
| void NodeConnection::DeprecatedGetAttr(DeprecatedGetAttrCompleter::Sync& completer) { |
| #else |
| void NodeConnection::GetAttr(GetAttrCompleter::Sync& completer) { |
| #endif // FUCHSIA_API_LEVEL_AT_LEAST(28) |
| zx::result attrs = vnode()->GetAttributes(); |
| if (attrs.is_ok()) { |
| completer.Reply(ZX_OK, attrs->ToIoV1NodeAttributes(*vnode())); |
| } else { |
| completer.Reply(attrs.error_value(), fio::wire::NodeAttributes()); |
| } |
| } |
| |
| #if FUCHSIA_API_LEVEL_AT_LEAST(28) |
| void NodeConnection::DeprecatedSetAttr(DeprecatedSetAttrRequestView request, |
| DeprecatedSetAttrCompleter::Sync& completer) { |
| #else |
| void NodeConnection::SetAttr(SetAttrRequestView request, SetAttrCompleter::Sync& completer) { |
| #endif // FUCHSIA_API_LEVEL_AT_LEAST(28) |
| completer.Reply(ZX_ERR_BAD_HANDLE); |
| } |
| |
| void NodeConnection::GetAttributes(fio::wire::NodeGetAttributesRequest* request, |
| GetAttributesCompleter::Sync& completer) { |
| // TODO(https://fxbug.dev/346585458): This operation should require the GET_ATTRIBUTES right. |
| internal::NodeAttributeBuilder builder(vnode()); |
| completer.Reply(builder.Build(request->query)); |
| } |
| |
| void NodeConnection::UpdateAttributes(fio::wire::MutableNodeAttributes* request, |
| UpdateAttributesCompleter::Sync& completer) { |
| completer.ReplyError(ZX_ERR_BAD_HANDLE); |
| } |
| |
| #if FUCHSIA_API_LEVEL_AT_LEAST(27) |
| void NodeConnection::GetFlags(GetFlagsCompleter::Sync& completer) { |
| completer.ReplySuccess(fio::Flags::kProtocolNode | RightsToFlags(rights())); |
| } |
| void NodeConnection::SetFlags(SetFlagsRequestView, SetFlagsCompleter::Sync& completer) { |
| completer.ReplyError(ZX_ERR_NOT_SUPPORTED); |
| } |
| #endif // FUCHSIA_API_LEVEL_AT_LEAST(27) |
| |
| #if FUCHSIA_API_LEVEL_AT_LEAST(27) |
| void NodeConnection::DeprecatedGetFlags(DeprecatedGetFlagsCompleter::Sync& completer) { |
| #else |
| void NodeConnection::GetFlags(GetFlagsCompleter::Sync& completer) { |
| #endif // FUCHSIA_API_LEVEL_AT_LEAST(27) |
| completer.Reply(ZX_OK, fio::OpenFlags::kNodeReference); |
| } |
| |
| #if FUCHSIA_API_LEVEL_AT_LEAST(27) |
| void NodeConnection::DeprecatedSetFlags(DeprecatedSetFlagsRequestView, |
| DeprecatedSetFlagsCompleter::Sync& completer) { |
| #else |
| void NodeConnection::SetFlags(SetFlagsRequestView, SetFlagsCompleter::Sync& completer) { |
| #endif // FUCHSIA_API_LEVEL_AT_LEAST(27) |
| completer.Reply(ZX_ERR_BAD_HANDLE); |
| } |
| |
| void NodeConnection::QueryFilesystem(QueryFilesystemCompleter::Sync& completer) { |
| zx::result result = Connection::NodeQueryFilesystem(); |
| completer.Reply(result.status_value(), |
| result.is_ok() |
| ? fidl::ObjectView<fio::wire::FilesystemInfo>::FromExternal(&result.value()) |
| : nullptr); |
| } |
| |
| zx::result<> NodeConnection::WithRepresentation( |
| fit::callback<zx::result<>(fio::wire::Representation)> handler, |
| std::optional<fio::NodeAttributesQuery> query) const { |
| #if FUCHSIA_API_LEVEL_AT_LEAST(27) |
| using NodeRepresentation = fio::wire::NodeInfo; |
| #else |
| using NodeRepresentation = fio::wire::ConnectorInfo; |
| #endif // FUCHSIA_API_LEVEL_AT_LEAST(27) |
| fidl::WireTableFrame<NodeRepresentation> representation_frame; |
| auto builder = NodeRepresentation::ExternalBuilder( |
| fidl::ObjectView<fidl::WireTableFrame<NodeRepresentation>>::FromExternal( |
| &representation_frame)); |
| std::optional<NodeAttributeBuilder> attributes_builder; |
| if (query) { |
| attributes_builder.emplace(vnode()); |
| zx::result<fio::wire::NodeAttributes2*> attributes = attributes_builder->Build(*query); |
| if (attributes.is_error()) { |
| return attributes.take_error(); |
| } |
| builder.attributes(fidl::ObjectView<fio::wire::NodeAttributes2>::FromExternal(*attributes)); |
| } |
| auto representation = builder.Build(); |
| #if FUCHSIA_API_LEVEL_AT_LEAST(27) |
| return handler(fuchsia_io::wire::Representation::WithNode( |
| fidl::ObjectView<NodeRepresentation>::FromExternal(&representation))); |
| #else |
| return handler(fuchsia_io::wire::Representation::WithConnector( |
| fidl::ObjectView<NodeRepresentation>::FromExternal(&representation))); |
| #endif // FUCHSIA_API_LEVEL_AT_LEAST(27) |
| } |
| |
| zx_status_t NodeConnection::WithNodeInfoDeprecated( |
| fit::callback<zx_status_t(fuchsia_io::wire::NodeInfoDeprecated)> handler) const { |
| // In io1, node reference connections are mapped to the service variant of NodeInfoDeprecated. |
| return handler(fuchsia_io::wire::NodeInfoDeprecated::WithService({})); |
| } |
| |
| } // namespace fs::internal |