blob: cd1280abba25375aefaa6e980e4eb7138394fb1c [file] [log] [blame]
// 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.
use {
crate::{
capability::CapabilitySource,
model::{
component::ComponentInstance,
error::ModelError,
routing::{RouteRequest, RouteSource},
},
},
fidl_fuchsia_io as fio, fuchsia_zircon as zx,
std::{path::PathBuf, sync::Arc},
};
/// A container for the data needed to open a capability.
pub enum OpenOptions<'a> {
Directory(OpenDirectoryOptions<'a>),
EventStream(OpenEventStreamOptions<'a>),
Protocol(OpenProtocolOptions<'a>),
Resolver(OpenResolverOptions<'a>),
Runner(OpenRunnerOptions<'a>),
Service(OpenServiceOptions<'a>),
Storage(OpenStorageOptions<'a>),
}
impl<'a> OpenOptions<'a> {
/// Creates an `OpenOptions` for a capability that can be installed in a namespace,
/// or an error if `route_request` specifies a capability that cannot be installed
/// in a namespace.
pub fn for_namespace_capability(
route_request: &RouteRequest,
flags: fio::OpenFlags,
open_mode: u32,
relative_path: String,
server_chan: &'a mut zx::Channel,
) -> Result<Self, ModelError> {
match route_request {
RouteRequest::UseDirectory(_) | RouteRequest::ExposeDirectory(_) => {
Ok(Self::Directory(OpenDirectoryOptions {
flags,
open_mode,
relative_path,
server_chan,
}))
}
RouteRequest::UseProtocol(_) | RouteRequest::ExposeProtocol(_) => {
Ok(Self::Protocol(OpenProtocolOptions {
flags,
open_mode,
relative_path,
server_chan,
}))
}
RouteRequest::UseService(_) | RouteRequest::ExposeService(_) => {
Ok(Self::Service(OpenServiceOptions {
flags,
open_mode,
relative_path,
server_chan,
}))
}
RouteRequest::UseEventStream(_) => Ok(Self::EventStream(OpenEventStreamOptions {
flags,
open_mode,
relative_path,
server_chan,
})),
RouteRequest::UseStorage(_) => {
Ok(Self::Storage(OpenStorageOptions { flags, open_mode, server_chan }))
}
_ => Err(ModelError::unsupported("capability cannot be installed in a namespace")),
}
}
}
pub struct OpenDirectoryOptions<'a> {
pub flags: fio::OpenFlags,
pub open_mode: u32,
pub relative_path: String,
pub server_chan: &'a mut zx::Channel,
}
pub struct OpenProtocolOptions<'a> {
pub flags: fio::OpenFlags,
pub open_mode: u32,
pub relative_path: String,
pub server_chan: &'a mut zx::Channel,
}
pub struct OpenResolverOptions<'a> {
pub flags: fio::OpenFlags,
pub open_mode: u32,
pub server_chan: &'a mut zx::Channel,
}
pub struct OpenRunnerOptions<'a> {
pub flags: fio::OpenFlags,
pub open_mode: u32,
pub server_chan: &'a mut zx::Channel,
}
pub struct OpenServiceOptions<'a> {
pub flags: fio::OpenFlags,
pub open_mode: u32,
pub relative_path: String,
pub server_chan: &'a mut zx::Channel,
}
pub struct OpenStorageOptions<'a> {
pub flags: fio::OpenFlags,
pub open_mode: u32,
pub server_chan: &'a mut zx::Channel,
}
pub struct OpenEventStreamOptions<'a> {
pub flags: fio::OpenFlags,
pub open_mode: u32,
pub relative_path: String,
pub server_chan: &'a mut zx::Channel,
}
/// A request to open a capability at its source.
pub struct OpenRequest<'a> {
pub flags: fio::OpenFlags,
pub open_mode: u32,
pub relative_path: PathBuf,
pub source: CapabilitySource,
pub target: &'a Arc<ComponentInstance>,
pub server_chan: &'a mut zx::Channel,
}
impl<'a> OpenRequest<'a> {
/// Creates a request to open a capability with source `route_source` for `target`.
pub fn new(
route_source: RouteSource,
target: &'a Arc<ComponentInstance>,
options: OpenOptions<'a>,
) -> Self {
match route_source {
RouteSource::Directory(source, directory_state) => {
if let OpenOptions::Directory(open_dir_options) = options {
return Self {
flags: open_dir_options.flags,
open_mode: open_dir_options.open_mode,
relative_path: directory_state
.make_relative_path(open_dir_options.relative_path),
source,
target,
server_chan: open_dir_options.server_chan,
};
}
}
RouteSource::Protocol(source) => {
if let OpenOptions::Protocol(open_protocol_options) = options {
return Self {
flags: open_protocol_options.flags,
open_mode: open_protocol_options.open_mode,
relative_path: PathBuf::from(open_protocol_options.relative_path),
source,
target,
server_chan: open_protocol_options.server_chan,
};
}
}
RouteSource::Service(source) => {
if let OpenOptions::Service(open_service_options) = options {
return Self {
flags: open_service_options.flags,
open_mode: open_service_options.open_mode,
relative_path: PathBuf::from(open_service_options.relative_path),
source,
target,
server_chan: open_service_options.server_chan,
};
}
}
RouteSource::Resolver(source) => {
if let OpenOptions::Resolver(open_resolver_options) = options {
return Self {
flags: open_resolver_options.flags,
open_mode: open_resolver_options.open_mode,
relative_path: PathBuf::new(),
source,
target,
server_chan: open_resolver_options.server_chan,
};
}
}
RouteSource::Runner(source) => {
if let OpenOptions::Runner(open_runner_options) = options {
return Self {
flags: open_runner_options.flags,
open_mode: open_runner_options.open_mode,
relative_path: PathBuf::new(),
source,
target,
server_chan: open_runner_options.server_chan,
};
}
}
RouteSource::EventStream(source) => {
if let OpenOptions::EventStream(open_event_stream_options) = options {
return Self {
flags: open_event_stream_options.flags,
open_mode: open_event_stream_options.open_mode,
relative_path: PathBuf::new(),
source,
target,
server_chan: open_event_stream_options.server_chan,
};
}
}
_ => panic!("unsupported route source"),
}
panic!("route source type did not match option type")
}
}