| // Copyright 2022 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::CapabilityProvider, |
| model::{component::WeakComponentInstance, routing::router_ext::WeakComponentTokenExt}, |
| sandbox_util::DictExt, |
| }, |
| ::routing::error::RoutingError, |
| async_trait::async_trait, |
| clonable_error::ClonableError, |
| cm_rust::Availability, |
| cm_types::{Name, OPEN_FLAGS_MAX_POSSIBLE_RIGHTS}, |
| cm_util::TaskGroup, |
| errors::{CapabilityProviderError, OpenError}, |
| router_error::RouterError, |
| sandbox::Request, |
| sandbox::WeakComponentToken, |
| std::sync::Arc, |
| vfs::{directory::entry::OpenRequest, path::Path as VfsPath, remote::remote_dir}, |
| }; |
| |
| /// The default provider for a ComponentCapability. |
| /// This provider will start the source component instance and open the capability `name` at |
| /// `path` under the source component's outgoing namespace. |
| pub struct DefaultComponentCapabilityProvider { |
| target: WeakComponentInstance, |
| source: WeakComponentInstance, |
| name: Name, |
| } |
| |
| impl DefaultComponentCapabilityProvider { |
| pub fn new(target: WeakComponentInstance, source: WeakComponentInstance, name: Name) -> Self { |
| DefaultComponentCapabilityProvider { target, source, name } |
| } |
| } |
| |
| #[async_trait] |
| impl CapabilityProvider for DefaultComponentCapabilityProvider { |
| async fn open( |
| self: Box<Self>, |
| _task_group: TaskGroup, |
| open_request: OpenRequest<'_>, |
| ) -> Result<(), CapabilityProviderError> { |
| let source = self.source.upgrade()?; |
| let capability = source |
| .get_program_output_dict() |
| .await? |
| .get_with_request( |
| &self.name, |
| // Routers in `program_output_dict` do not check availability but we need a |
| // request to run hooks. |
| Request { |
| availability: Availability::Transitional, |
| target: WeakComponentToken::new(self.target.clone()), |
| }, |
| ) |
| .await? |
| .ok_or_else(|| RoutingError::BedrockNotPresentInDictionary { |
| name: self.name.to_string(), |
| }) |
| .map_err(RouterError::from)?; |
| let entry = capability |
| .try_into_directory_entry() |
| .map_err(OpenError::DoesNotSupportOpen) |
| .map_err(RouterError::from)?; |
| entry.open_entry(open_request).map_err(|err| CapabilityProviderError::VfsOpenError(err)) |
| } |
| } |
| |
| /// The default provider for a Namespace Capability. |
| pub struct NamespaceCapabilityProvider { |
| pub path: cm_types::Path, |
| pub is_directory_like: bool, |
| } |
| |
| #[async_trait] |
| impl CapabilityProvider for NamespaceCapabilityProvider { |
| async fn open( |
| self: Box<Self>, |
| _task_group: TaskGroup, |
| mut open_request: OpenRequest<'_>, |
| ) -> Result<(), CapabilityProviderError> { |
| let path = self.path.to_path_buf(); |
| let (dir, base) = if self.is_directory_like { |
| (path.to_str().ok_or(CapabilityProviderError::BadPath)?, VfsPath::dot()) |
| } else { |
| ( |
| match path.parent() { |
| None => "/", |
| Some(p) => p.to_str().ok_or(CapabilityProviderError::BadPath)?, |
| }, |
| path.file_name() |
| .and_then(|f| f.to_str()) |
| .ok_or(CapabilityProviderError::BadPath)? |
| .try_into() |
| .map_err(|_| CapabilityProviderError::BadPath)?, |
| ) |
| }; |
| |
| open_request.prepend_path(&base); |
| |
| open_request |
| .open_remote(remote_dir( |
| fuchsia_fs::directory::open_in_namespace(dir, OPEN_FLAGS_MAX_POSSIBLE_RIGHTS) |
| .map_err(|e| CapabilityProviderError::CmNamespaceError { |
| err: ClonableError::from(anyhow::Error::from(e)), |
| })?, |
| )) |
| .map_err(|e| CapabilityProviderError::CmNamespaceError { |
| err: ClonableError::from(anyhow::Error::from(e)), |
| }) |
| } |
| } |
| |
| /// A `CapabilityProvider` that serves a pseudo directory entry. |
| #[derive(Clone)] |
| pub struct DirectoryEntryCapabilityProvider { |
| /// The pseudo directory that backs this capability. |
| pub entry: Arc<vfs::directory::immutable::simple::Simple>, |
| } |
| |
| #[async_trait] |
| impl CapabilityProvider for DirectoryEntryCapabilityProvider { |
| async fn open( |
| self: Box<Self>, |
| _task_group: TaskGroup, |
| open_request: OpenRequest<'_>, |
| ) -> Result<(), CapabilityProviderError> { |
| open_request |
| .open_dir(self.entry.clone()) |
| .map_err(|e| CapabilityProviderError::VfsOpenError(e)) |
| } |
| } |