1use fdio::Namespace;
6use fidl::endpoints::Proxy;
7use fidl_fuchsia_component as fcomponent;
8use fuchsia_component::client::connect_to_protocol;
9use std::fmt::Debug;
10use uuid::Uuid;
11
12#[cfg(fuchsia_api_level_at_least = "HEAD")]
13use fidl_fuchsia_component_sandbox as _;
14#[cfg(fuchsia_api_level_less_than = "HEAD")]
15use {fidl::endpoints::ClientEnd, fidl_fuchsia_component_sandbox as fsandbox};
16
17mod error;
18pub use error::Error;
19
20pub struct InstalledNamespace {
31 prefix: String,
32
33 _realm_factory: fidl::AsyncChannel,
38}
39
40impl InstalledNamespace {
41 pub fn prefix(&self) -> &str {
42 &self.prefix
43 }
44}
45
46impl Drop for InstalledNamespace {
47 fn drop(&mut self) {
48 let Ok(namespace) = Namespace::installed() else {
49 return;
50 };
51 let _ = namespace.unbind(&self.prefix);
52 }
53}
54
55impl AsRef<str> for &InstalledNamespace {
56 fn as_ref(&self) -> &str {
57 self.prefix()
58 }
59}
60
61pub async fn extend_namespace<T>(
73 realm_factory: T,
74 #[cfg(fuchsia_api_level_at_least = "HEAD")] capability: zx::EventPair,
75 #[cfg(fuchsia_api_level_less_than = "HEAD")] dictionary: ClientEnd<fsandbox::DictionaryMarker>,
76) -> Result<InstalledNamespace, error::Error>
77where
78 T: Proxy + Debug,
79{
80 let namespace_proxy = connect_to_protocol::<fcomponent::NamespaceMarker>()
81 .map_err(|e| error::Error::ConnectionFailed(format!("{:?}", e)))?;
82 let prefix = format!("/dict-{}", Uuid::new_v4());
86 #[cfg(fuchsia_api_level_at_least = "HEAD")]
87 let mut namespace_entries = {
88 let dicts =
89 vec![fcomponent::NamespaceInputEntry2 { path: prefix.clone().into(), capability }];
90 namespace_proxy.create2(dicts).await?.map_err(error::Error::NamespaceCreation)?
91 };
92 #[cfg(fuchsia_api_level_less_than = "HEAD")]
93 let mut namespace_entries = {
94 let dicts =
95 vec![fcomponent::NamespaceInputEntry { path: prefix.clone().into(), dictionary }];
96 namespace_proxy.create(dicts).await?.map_err(error::Error::NamespaceCreation)?
97 };
98 let namespace = Namespace::installed().map_err(error::Error::NamespaceNotInstalled)?;
99 let count = namespace_entries.len();
100 if count != 1 {
101 return Err(error::Error::InvalidNamespaceEntryCount { prefix, count });
102 }
103 let entry = namespace_entries.remove(0);
104 if entry.path.is_none() || entry.directory.is_none() {
105 return Err(error::Error::EntryIncomplete { prefix, message: format!("{:?}", entry) });
106 }
107 if entry.path.as_ref().unwrap() != &prefix {
108 return Err(error::Error::PrefixDoesNotMatchPath {
109 prefix,
110 path: format!("{:?}", entry.path),
111 });
112 }
113 namespace.bind(&prefix, entry.directory.unwrap()).map_err(error::Error::NamespaceBind)?;
114 Ok(InstalledNamespace { prefix, _realm_factory: realm_factory.into_channel().unwrap() })
115}