blob: 82ea83872fc4eb1925ca5e8b0edd2daa82c7c07c [file] [log] [blame]
// Copyright 2020 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::error::Error,
crate::{AnyRef, Capability, RightsClause},
cm_types::Name,
fidl_fuchsia_io2 as fio2, fidl_fuchsia_sys2 as fsys,
std::collections::HashSet,
std::convert::Into,
};
pub fn translate_capabilities(
capabilities_in: &Vec<Capability>,
) -> Result<Vec<fsys::CapabilityDecl>, Error> {
let mut out_capabilities = vec![];
for capability in capabilities_in {
if let Some(n) = &capability.service {
let source_path =
capability.path.clone().unwrap_or_else(|| format!("/svc/{}", n).parse().unwrap());
out_capabilities.push(fsys::CapabilityDecl::Service(fsys::ServiceDecl {
name: Some(n.clone().into()),
source_path: Some(source_path.into()),
..fsys::ServiceDecl::EMPTY
}));
} else if let Some(protocol) = &capability.protocol {
for n in protocol.to_vec() {
let source_path = capability
.path
.clone()
.unwrap_or_else(|| format!("/svc/{}", n).parse().unwrap());
out_capabilities.push(fsys::CapabilityDecl::Protocol(fsys::ProtocolDecl {
name: Some(n.clone().into()),
source_path: Some(source_path.into()),
..fsys::ProtocolDecl::EMPTY
}));
}
} else if let Some(n) = &capability.directory {
let source_path =
capability.path.clone().unwrap_or_else(|| format!("/svc/{}", n).parse().unwrap());
let rights = extract_required_rights(capability, "capability")?;
out_capabilities.push(fsys::CapabilityDecl::Directory(fsys::DirectoryDecl {
name: Some(n.clone().into()),
source_path: Some(source_path.into()),
rights: Some(rights),
..fsys::DirectoryDecl::EMPTY
}));
} else if let Some(n) = &capability.storage {
let backing_dir = capability
.backing_dir
.as_ref()
.expect("storage has no path or backing_dir")
.clone()
.into();
out_capabilities.push(fsys::CapabilityDecl::Storage(fsys::StorageDecl {
name: Some(n.clone().into()),
backing_dir: Some(backing_dir),
source: Some(offer_source_from_ref(
capability.from.as_ref().unwrap().into(),
None,
)?),
subdir: capability.subdir.clone().map(Into::into),
..fsys::StorageDecl::EMPTY
}));
} else if let Some(n) = &capability.runner {
out_capabilities.push(fsys::CapabilityDecl::Runner(fsys::RunnerDecl {
name: Some(n.clone().into()),
source_path: Some(capability.path.clone().expect("missing path").into()),
source: Some(offer_source_from_ref(
capability.from.as_ref().unwrap().into(),
None,
)?),
..fsys::RunnerDecl::EMPTY
}));
} else if let Some(n) = &capability.resolver {
out_capabilities.push(fsys::CapabilityDecl::Resolver(fsys::ResolverDecl {
name: Some(n.clone().into()),
source_path: Some(capability.path.clone().expect("missing path").into()),
..fsys::ResolverDecl::EMPTY
}));
} else {
return Err(Error::internal(format!("no capability in use declaration")));
}
}
Ok(out_capabilities)
}
pub fn extract_required_rights<T>(in_obj: &T, keyword: &str) -> Result<fio2::Operations, Error>
where
T: RightsClause,
{
match in_obj.rights() {
Some(rights_tokens) => {
let mut rights = Vec::new();
for token in rights_tokens.0.iter() {
rights.append(&mut token.expand())
}
if rights.is_empty() {
return Err(Error::missing_rights(format!(
"Rights provided to `{}` are not well formed.",
keyword
)));
}
let mut seen_rights = HashSet::with_capacity(rights.len());
let mut operations: fio2::Operations = fio2::Operations::empty();
for right in rights.iter() {
if seen_rights.contains(&right) {
return Err(Error::duplicate_rights(format!(
"Rights provided to `{}` are not well formed.",
keyword
)));
}
seen_rights.insert(right);
operations |= *right;
}
Ok(operations)
}
None => Err(Error::internal(format!(
"No `{}` rights provided but required for directories",
keyword
))),
}
}
pub fn offer_source_from_ref(
reference: AnyRef<'_>,
all_capability_names: Option<&HashSet<Name>>,
) -> Result<fsys::Ref, Error> {
match reference {
AnyRef::Named(name) => {
if all_capability_names.is_some() && all_capability_names.unwrap().contains(&name) {
return Ok(fsys::Ref::Capability(fsys::CapabilityRef {
name: name.clone().into(),
}));
}
Ok(fsys::Ref::Child(fsys::ChildRef { name: name.clone().into(), collection: None }))
}
AnyRef::Framework => Ok(fsys::Ref::Framework(fsys::FrameworkRef {})),
AnyRef::Parent => Ok(fsys::Ref::Parent(fsys::ParentRef {})),
AnyRef::Self_ => Ok(fsys::Ref::Self_(fsys::SelfRef {})),
}
}