blob: 23f38035c1fe3ff4fb603fe8372f2b59cd39181a [file] [log] [blame]
// 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/lib/storage/vfs/cpp/vfs_types.h"
#include <fidl/fuchsia.io/cpp/wire.h>
#include <lib/fdio/vfs.h>
#include <lib/fit/function.h>
namespace fio = fuchsia_io;
namespace fs {
VnodeConnectionOptions VnodeConnectionOptions::FromIoV1Flags(
fuchsia_io::wire::OpenFlags fidl_flags) {
VnodeConnectionOptions options;
// Flags:
if (fidl_flags & fio::wire::OpenFlags::kCreate) {
options.flags.create = true;
}
if (fidl_flags & fio::wire::OpenFlags::kCreateIfAbsent) {
options.flags.fail_if_exists = true;
}
if (fidl_flags & fio::wire::OpenFlags::kTruncate) {
options.flags.truncate = true;
}
if (fidl_flags & fio::wire::OpenFlags::kDirectory) {
options.flags.directory = true;
}
if (fidl_flags & fio::wire::OpenFlags::kAppend) {
options.flags.append = true;
}
if (fidl_flags & fio::wire::OpenFlags::kNodeReference) {
options.flags.node_reference = true;
}
if (fidl_flags & fio::wire::OpenFlags::kDescribe) {
options.flags.describe = true;
}
// Expand deprecated POSIX flag into new equivalents to maintain binary compatibility with
// out-of-tree clients while still preventing rights escalations when crossing remote mounts.
// TODO(fxbug.dev/81185): Remove kOpenFlagPosixDeprecated.
if (fidl_flags & fio::wire::OpenFlags::kPosixDeprecated) {
options.flags.posix_write = true;
options.flags.posix_execute = true;
}
if (fidl_flags & fio::wire::OpenFlags::kPosixWritable) {
options.flags.posix_write = true;
}
if (fidl_flags & fio::wire::OpenFlags::kPosixExecutable) {
options.flags.posix_execute = true;
}
if (fidl_flags & fio::wire::OpenFlags::kNotDirectory) {
options.flags.not_directory = true;
}
if (fidl_flags & fio::wire::OpenFlags::kCloneSameRights) {
options.flags.clone_same_rights = true;
}
// Rights (these are smushed into |fidl_flags| in fuchsia.io v1):
if (fidl_flags & fio::wire::OpenFlags::kRightReadable) {
options.rights.read = true;
}
if (fidl_flags & fio::wire::OpenFlags::kRightWritable) {
options.rights.write = true;
}
if (fidl_flags & fio::wire::OpenFlags::kRightExecutable) {
options.rights.execute = true;
}
return options;
}
fuchsia_io::wire::OpenFlags VnodeConnectionOptions::ToIoV1Flags() const {
fuchsia_io::wire::OpenFlags fidl_flags = {};
// Flags:
if (flags.create) {
fidl_flags |= fio::wire::OpenFlags::kCreate;
}
if (flags.fail_if_exists) {
fidl_flags |= fio::wire::OpenFlags::kCreateIfAbsent;
}
if (flags.truncate) {
fidl_flags |= fio::wire::OpenFlags::kTruncate;
}
if (flags.directory) {
fidl_flags |= fio::wire::OpenFlags::kDirectory;
}
if (flags.append) {
fidl_flags |= fio::wire::OpenFlags::kAppend;
}
if (flags.node_reference) {
fidl_flags |= fio::wire::OpenFlags::kNodeReference;
}
if (flags.describe) {
fidl_flags |= fio::wire::OpenFlags::kDescribe;
}
if (flags.posix_write) {
fidl_flags |= fio::wire::OpenFlags::kPosixWritable;
}
if (flags.posix_execute) {
fidl_flags |= fio::wire::OpenFlags::kPosixExecutable;
}
if (flags.not_directory) {
fidl_flags |= fio::wire::OpenFlags::kNotDirectory;
}
if (flags.clone_same_rights) {
fidl_flags |= fio::wire::OpenFlags::kCloneSameRights;
}
// Rights (these are smushed into |fidl_flags| in fuchsia.io v1):
if (rights.read) {
fidl_flags |= fio::wire::OpenFlags::kRightReadable;
}
if (rights.write) {
fidl_flags |= fio::wire::OpenFlags::kRightWritable;
}
if (rights.execute) {
fidl_flags |= fio::wire::OpenFlags::kRightExecutable;
}
return fidl_flags;
}
VnodeConnectionOptions VnodeConnectionOptions::FilterForNewConnection(
VnodeConnectionOptions options) {
VnodeConnectionOptions result;
result.flags.append = options.flags.append;
result.flags.node_reference = options.flags.node_reference;
result.rights = options.rights;
return result;
}
fio::wire::NodeAttributes VnodeAttributes::ToIoV1NodeAttributes() const {
return fio::wire::NodeAttributes{.mode = mode,
.id = inode,
.content_size = content_size,
.storage_size = storage_size,
.link_count = link_count,
.creation_time = creation_time,
.modification_time = modification_time};
}
void ConvertToIoV1NodeInfo(VnodeRepresentation representation,
fit::callback<void(fio::wire::NodeInfo&&)> callback) {
representation.visit([&](auto&& repr) {
using T = std::decay_t<decltype(repr)>;
if constexpr (std::is_same_v<T, fs::VnodeRepresentation::Connector>) {
callback(fio::wire::NodeInfo::WithService({}));
} else if constexpr (std::is_same_v<T, fs::VnodeRepresentation::File>) {
fio::wire::FileObject file = {.event = std::move(repr.observer),
.stream = std::move(repr.stream)};
callback(fio::wire::NodeInfo::WithFile(
fidl::ObjectView<fio::wire::FileObject>::FromExternal(&file)));
} else if constexpr (std::is_same_v<T, fs::VnodeRepresentation::Directory>) {
callback(fio::wire::NodeInfo::WithDirectory({}));
} else if constexpr (std::is_same_v<T, fs::VnodeRepresentation::Pipe>) {
callback(fio::wire::NodeInfo::WithPipe({.socket = std::move(repr.socket)}));
} else if constexpr (std::is_same_v<T, fs::VnodeRepresentation::Memory>) {
fio::wire::Vmofile vmofile = {
.vmo = std::move(repr.vmo), .offset = repr.offset, .length = repr.length};
callback(fio::wire::NodeInfo::WithVmofile(
fidl::ObjectView<fio::wire::Vmofile>::FromExternal(&vmofile)));
} else if constexpr (std::is_same_v<T, fs::VnodeRepresentation::Device>) {
callback(fio::wire::NodeInfo::WithDevice({}));
} else if constexpr (std::is_same_v<T, fs::VnodeRepresentation::Tty>) {
callback(fio::wire::NodeInfo::WithTty({.event = std::move(repr.event)}));
} else if constexpr (std::is_same_v<T, fs::VnodeRepresentation::SynchronousDatagramSocket>) {
callback(
fio::wire::NodeInfo::WithSynchronousDatagramSocket({.event = std::move(repr.event)}));
} else if constexpr (std::is_same_v<T, fs::VnodeRepresentation::DatagramSocket>) {
fio::wire::DatagramSocket datagram_socket = {
.socket = std::move(repr.socket),
.tx_meta_buf_size = repr.tx_meta_buf_size,
.rx_meta_buf_size = repr.rx_meta_buf_size,
};
callback(fio::wire::NodeInfo::WithDatagramSocket(
fidl::ObjectView<fio::wire::DatagramSocket>::FromExternal(&datagram_socket)));
} else if constexpr (std::is_same_v<T, fs::VnodeRepresentation::StreamSocket>) {
callback(fio::wire::NodeInfo::WithStreamSocket({.socket = std::move(repr.socket)}));
} else {
ZX_PANIC("Representation variant is not initialized");
}
});
}
ConnectionInfoConverter::ConnectionInfoConverter(VnodeRepresentation representation) : info(arena) {
representation.visit([&](auto&& repr) {
using T = std::decay_t<decltype(repr)>;
if constexpr (std::is_same_v<T, fs::VnodeRepresentation::Connector>) {
info.set_representation(arena, fio::wire::Representation::WithConnector(arena));
} else if constexpr (std::is_same_v<T, fs::VnodeRepresentation::File>) {
fio::wire::FileInfo file(arena);
file.set_observer(std::move(repr.observer));
file.set_stream(std::move(repr.stream));
info.set_representation(arena, fio::wire::Representation::WithFile(arena, std::move(file)));
} else if constexpr (std::is_same_v<T, fs::VnodeRepresentation::Directory>) {
info.set_representation(arena, fio::wire::Representation::WithDirectory(arena));
} else if constexpr (std::is_same_v<T, fs::VnodeRepresentation::Pipe>) {
fio::wire::PipeInfo pipe(arena);
pipe.set_socket(std::move(repr.socket));
info.set_representation(arena, fio::wire::Representation::WithPipe(arena, std::move(pipe)));
} else if constexpr (std::is_same_v<T, fs::VnodeRepresentation::Memory>) {
fio::wire::MemoryInfo memory(arena);
memory.set_buffer(arena, fuchsia_mem::wire::Range{
.vmo = std::move(repr.vmo),
.offset = repr.offset,
.size = repr.length,
});
info.set_representation(arena, fio::wire::Representation::WithMemory(arena, memory));
} else if constexpr (std::is_same_v<T, fs::VnodeRepresentation::Device>) {
fio::wire::DeviceInfo device(arena);
info.set_representation(arena,
fio::wire::Representation::WithDevice(arena, std::move(device)));
} else if constexpr (std::is_same_v<T, fs::VnodeRepresentation::Tty>) {
fio::wire::TtyInfo tty(arena);
tty.set_event(std::move(repr.event));
info.set_representation(arena, fio::wire::Representation::WithTty(arena, std::move(tty)));
} else if constexpr (std::is_same_v<T, fs::VnodeRepresentation::SynchronousDatagramSocket>) {
fio::wire::SynchronousDatagramSocketInfo synchronous_datagram_socket(arena);
synchronous_datagram_socket.set_event(std::move(repr.event));
info.set_representation(arena, fio::wire::Representation::WithSynchronousDatagramSocket(
arena, std::move(synchronous_datagram_socket)));
} else if constexpr (std::is_same_v<T, fs::VnodeRepresentation::DatagramSocket>) {
fio::wire::DatagramSocketInfo datagram_socket(arena);
datagram_socket.set_socket(std::move(repr.socket));
datagram_socket.set_tx_meta_buf_size(arena, repr.tx_meta_buf_size);
datagram_socket.set_rx_meta_buf_size(arena, repr.rx_meta_buf_size);
info.set_representation(
arena, fio::wire::Representation::WithDatagramSocket(arena, std::move(datagram_socket)));
} else if constexpr (std::is_same_v<T, fs::VnodeRepresentation::StreamSocket>) {
fio::wire::StreamSocketInfo stream_socket(arena);
stream_socket.set_socket(std::move(repr.socket));
info.set_representation(
arena, fio::wire::Representation::WithStreamSocket(arena, std::move(stream_socket)));
} else {
ZX_PANIC("Representation variant is not initialized");
}
});
}
} // namespace fs