1use crate::dictionary::Key;
6use crate::fidl::{IntoFsandboxCapability, RemotableCapability, registry};
7use crate::{Capability, Connector, Dictionary, DirConnector, WeakInstanceToken};
8use cm_types::RelativePath;
9use fidl::handle::Signals;
10use fidl_fuchsia_component_decl as fdecl;
11use fidl_fuchsia_component_sandbox as fsandbox;
12use fidl_fuchsia_io as fio;
13use fuchsia_async as fasync;
14use futures::{FutureExt, TryStreamExt};
15use log::warn;
16use std::collections::HashMap;
17use std::collections::hash_map::Entry;
18use std::sync::{self, Arc, Weak};
19use vfs::ExecutionScope;
20use vfs::directory::entry::SubNode;
21use vfs::directory::helper::DirectlyMutable;
22use vfs::directory::simple::Simple;
23use vfs::path::Path;
24
25type Store = sync::Mutex<HashMap<u64, Capability>>;
26
27pub async fn serve_capability_store(
28 mut stream: fsandbox::CapabilityStoreRequestStream,
29 receiver_scope: &fasync::Scope,
37 token: WeakInstanceToken,
38) -> Result<(), fidl::Error> {
39 let outer_store: Arc<Store> = Arc::new(Store::new(Default::default()));
40 while let Some(request) = stream.try_next().await? {
41 let mut store = outer_store.lock().unwrap();
42 match request {
43 fsandbox::CapabilityStoreRequest::Duplicate { id, dest_id, responder } => {
44 let result = (|| {
45 let cap =
46 store.get(&id).ok_or(fsandbox::CapabilityStoreError::IdNotFound)?.clone();
47 insert_capability(&mut store, dest_id, cap)
48 })();
49 responder.send(result)?;
50 }
51 fsandbox::CapabilityStoreRequest::Drop { id, responder } => {
52 let result =
53 store.remove(&id).map(|_| ()).ok_or(fsandbox::CapabilityStoreError::IdNotFound);
54 responder.send(result)?;
55 }
56 fsandbox::CapabilityStoreRequest::Export { id, responder } => {
57 let result = (|| {
58 let cap =
59 store.remove(&id).ok_or(fsandbox::CapabilityStoreError::IdNotFound)?;
60 Ok(cap.into_fsandbox_capability(token.clone()))
61 })();
62 responder.send(result)?;
63 }
64 fsandbox::CapabilityStoreRequest::Import { id, capability, responder } => {
65 let result = (|| {
66 let capability = capability
67 .try_into()
68 .map_err(|_| fsandbox::CapabilityStoreError::BadCapability)?;
69 insert_capability(&mut store, id, capability)
70 })();
71 responder.send(result)?;
72 }
73 fsandbox::CapabilityStoreRequest::ConnectorCreate { id, receiver, responder } => {
74 let result = (|| {
75 let connector = Connector::new_with_fidl_receiver(receiver, receiver_scope);
76 insert_capability(&mut store, id, Capability::Connector(connector))
77 })();
78 responder.send(result)?;
79 }
80 fsandbox::CapabilityStoreRequest::ConnectorOpen { id, server_end, responder } => {
81 let result = (|| {
82 let this = get_connector(&store, id)?;
83 let _ = this.send(server_end);
84 Ok(())
85 })();
86 responder.send(result)?;
87 }
88 fsandbox::CapabilityStoreRequest::DirConnectorCreate { id, receiver, responder } => {
89 let result = (|| {
90 let connector = DirConnector::new_with_fidl_receiver(receiver, receiver_scope);
91 insert_capability(&mut store, id, Capability::DirConnector(connector))
92 })();
93 responder.send(result)?;
94 }
95 fsandbox::CapabilityStoreRequest::DirConnectorOpen { payload, responder } => {
96 let result = (|| {
97 let Some(id) = payload.id else {
98 return Err(fsandbox::CapabilityStoreError::InvalidArgs);
99 };
100 let Some(server_end) = payload.server_end else {
101 return Err(fsandbox::CapabilityStoreError::InvalidArgs);
102 };
103 let this = get_dir_connector(&store, id)?;
104 let path = payload
105 .path
106 .map(RelativePath::new)
107 .transpose()
108 .map_err(|_| fsandbox::CapabilityStoreError::InvalidArgs)?
109 .unwrap_or_else(|| RelativePath::dot());
110 let _ = this.send(server_end, path, payload.flags);
111 Ok(())
112 })();
113 responder.send(result)?;
114 }
115 fsandbox::CapabilityStoreRequest::DictionaryCreate { id, responder } => {
116 let result =
117 insert_capability(&mut store, id, Capability::Dictionary(Dictionary::new()));
118 responder.send(result)?;
119 }
120 fsandbox::CapabilityStoreRequest::DictionaryLegacyImport {
121 id,
122 client_end,
123 responder,
124 } => {
125 let result = (|| {
126 let capability = Dictionary::try_from(client_end)
127 .map_err(|_| fsandbox::CapabilityStoreError::BadCapability)?
128 .into();
129 insert_capability(&mut store, id, capability)
130 })();
131 responder.send(result)?;
132 }
133 fsandbox::CapabilityStoreRequest::DictionaryLegacyExport {
134 id,
135 server_end,
136 responder,
137 } => {
138 let result = (|| {
139 let cap =
140 store.remove(&id).ok_or(fsandbox::CapabilityStoreError::IdNotFound)?;
141 let Capability::Dictionary(_) = &cap else {
142 return Err(fsandbox::CapabilityStoreError::WrongType);
143 };
144 let koid = server_end.as_handle_ref().basic_info().unwrap().related_koid;
145 registry::insert(
146 cap,
147 koid,
148 fasync::OnSignals::new(server_end, Signals::OBJECT_PEER_CLOSED).map(|_| ()),
149 );
150 Ok(())
151 })();
152 responder.send(result)?
153 }
154 fsandbox::CapabilityStoreRequest::DictionaryInsert { id, item, responder } => {
155 let result = (|| {
156 let this = get_dictionary(&store, id)?;
157 let this = this.clone();
158 let key =
159 item.key.parse().map_err(|_| fsandbox::CapabilityStoreError::InvalidKey)?;
160 let value = store
161 .remove(&item.value)
162 .ok_or(fsandbox::CapabilityStoreError::IdNotFound)?;
163 if this.insert(key, value).is_some() {
164 Err(fsandbox::CapabilityStoreError::ItemAlreadyExists)
165 } else {
166 Ok(())
167 }
168 })();
169 responder.send(result)?;
170 }
171 fsandbox::CapabilityStoreRequest::DictionaryGet { id, key, dest_id, responder } => {
172 let result = (|| {
173 let this = get_dictionary(&store, id)?;
174 let key =
175 Key::new(key).map_err(|_| fsandbox::CapabilityStoreError::InvalidKey)?;
176 let cap = match this.get(&key) {
177 Some(cap) => Ok(cap),
178 None => {
179 this.not_found(key.as_str());
180 Err(fsandbox::CapabilityStoreError::ItemNotFound)
181 }
182 }?;
183 insert_capability(&mut store, dest_id, cap)
184 })();
185 responder.send(result)?;
186 }
187 fsandbox::CapabilityStoreRequest::DictionaryRemove { id, key, dest_id, responder } => {
188 let result = (|| {
189 let this = get_dictionary(&store, id)?;
190 let key =
191 Key::new(key).map_err(|_| fsandbox::CapabilityStoreError::InvalidKey)?;
192 if let Some(dest_id) = dest_id.as_ref() {
194 if store.contains_key(&dest_id.id) {
195 return Err(fsandbox::CapabilityStoreError::IdAlreadyExists);
196 }
197 }
198 let cap = match this.remove(&key) {
199 Some(cap) => Ok(cap.into()),
200 None => {
201 this.not_found(key.as_str());
202 Err(fsandbox::CapabilityStoreError::ItemNotFound)
203 }
204 }?;
205 if let Some(dest_id) = dest_id.as_ref() {
206 store.insert(dest_id.id, cap);
207 }
208 Ok(())
209 })();
210 responder.send(result)?;
211 }
212 fsandbox::CapabilityStoreRequest::DictionaryCopy { id, dest_id, responder } => {
213 let result = (|| {
214 let this = get_dictionary(&store, id)?;
215 let dict = this.shallow_copy();
216 insert_capability(&mut store, dest_id, Capability::Dictionary(dict))
217 })();
218 responder.send(result)?
219 }
220 fsandbox::CapabilityStoreRequest::DictionaryKeys {
221 id,
222 iterator: server_end,
223 responder,
224 } => {
225 let result = (|| {
226 let this = get_dictionary(&store, id)?;
227 let keys = this.snapshot_keys_as_strings().into_iter();
228 let stream = server_end.into_stream();
229 let mut this = this.lock();
230 this.tasks().spawn(serve_dictionary_keys_iterator(keys, stream));
231 Ok(())
232 })();
233 responder.send(result)?
234 }
235 fsandbox::CapabilityStoreRequest::DictionaryEnumerate {
236 id,
237 iterator: server_end,
238 responder,
239 } => {
240 let result = (|| {
241 let this = get_dictionary(&store, id)?;
242 let items = this.enumerate().map(|(k, v)| (k, Ok(v)));
243 let stream = server_end.into_stream();
244 let mut this = this.lock();
245 this.tasks().spawn(serve_dictionary_enumerate_iterator(
246 Arc::downgrade(&outer_store),
247 items,
248 stream,
249 ));
250 Ok(())
251 })();
252 responder.send(result)?
253 }
254 fsandbox::CapabilityStoreRequest::DictionaryDrain {
255 id,
256 iterator: server_end,
257 responder,
258 } => {
259 let result = (|| {
260 let this = get_dictionary(&store, id)?;
261 let items = this.drain();
264 if let Some(server_end) = server_end {
265 let stream = server_end.into_stream();
266 let mut this = this.lock();
267 this.tasks().spawn(serve_dictionary_drain_iterator(
268 Arc::downgrade(&outer_store),
269 items,
270 stream,
271 ));
272 }
273 Ok(())
274 })();
275 responder.send(result)?
276 }
277 fsandbox::CapabilityStoreRequest::CreateServiceAggregate { sources, responder } => {
278 drop(store);
282 responder.send(create_service_aggregate(token.clone(), sources).await)?;
283 }
284 fsandbox::CapabilityStoreRequest::_UnknownMethod { ordinal, .. } => {
285 warn!("Received unknown CapabilityStore request with ordinal {ordinal}");
286 }
287 }
288 }
289 Ok(())
290}
291
292async fn serve_dictionary_keys_iterator(
293 mut keys: impl Iterator<Item = String>,
294 mut stream: fsandbox::DictionaryKeysIteratorRequestStream,
295) {
296 while let Ok(Some(request)) = stream.try_next().await {
297 match request {
298 fsandbox::DictionaryKeysIteratorRequest::GetNext { responder } => {
299 let mut chunk = vec![];
300 for _ in 0..fsandbox::MAX_DICTIONARY_ITERATOR_CHUNK {
301 match keys.next() {
302 Some(key) => {
303 chunk.push(key.into());
304 }
305 None => break,
306 }
307 }
308 let _ = responder.send(&chunk);
309 }
310 fsandbox::DictionaryKeysIteratorRequest::_UnknownMethod { ordinal, .. } => {
311 warn!(ordinal:%; "Unknown DictionaryKeysIterator request");
312 }
313 }
314 }
315}
316
317async fn serve_dictionary_enumerate_iterator(
318 store: Weak<Store>,
319 mut items: impl Iterator<Item = (Key, Result<Capability, ()>)>,
320 mut stream: fsandbox::DictionaryEnumerateIteratorRequestStream,
321) {
322 while let Ok(Some(request)) = stream.try_next().await {
323 let Some(store) = store.upgrade() else {
324 return;
325 };
326 let mut store = store.lock().unwrap();
327 match request {
328 fsandbox::DictionaryEnumerateIteratorRequest::GetNext {
329 start_id,
330 limit,
331 responder,
332 } => {
333 let result = (|| {
334 let mut next_id = start_id;
335 let chunk = get_next_chunk(&*store, &mut items, &mut next_id, limit)?;
336 let end_id = next_id;
337
338 let chunk: Vec<_> = chunk
339 .into_iter()
340 .map(|(key, value)| {
341 if let Some((capability, id)) = value {
342 store.insert(id, capability);
343 fsandbox::DictionaryOptionalItem {
344 key: key.into(),
345 value: Some(Box::new(fsandbox::WrappedCapabilityId { id })),
346 }
347 } else {
348 fsandbox::DictionaryOptionalItem { key: key.into(), value: None }
349 }
350 })
351 .collect();
352 Ok((chunk, end_id))
353 })();
354 let err = result.is_err();
355 let _ = responder.send(result);
356 if err {
357 return;
358 }
359 }
360 fsandbox::DictionaryEnumerateIteratorRequest::_UnknownMethod { ordinal, .. } => {
361 warn!(ordinal:%; "Unknown DictionaryEnumerateIterator request");
362 }
363 }
364 }
365}
366
367async fn serve_dictionary_drain_iterator(
368 store: Weak<Store>,
369 items: impl Iterator<Item = (Key, Capability)>,
370 mut stream: fsandbox::DictionaryDrainIteratorRequestStream,
371) {
372 let mut items = items.map(|(key, capability)| (key, Ok(capability)));
374 while let Ok(Some(request)) = stream.try_next().await {
375 let Some(store) = store.upgrade() else {
376 return;
377 };
378 let mut store = store.lock().unwrap();
379 match request {
380 fsandbox::DictionaryDrainIteratorRequest::GetNext { start_id, limit, responder } => {
381 let result = (|| {
382 let mut next_id = start_id;
383 let chunk = get_next_chunk(&*store, &mut items, &mut next_id, limit)?;
384 let end_id = next_id;
385
386 let chunk: Vec<_> = chunk
387 .into_iter()
388 .map(|(key, value)| {
389 let value = value.expect("unreachable: all values are present");
390 let (capability, id) = value;
391 store.insert(id, capability);
392 fsandbox::DictionaryItem { key: key.into(), value: id }
393 })
394 .collect();
395 Ok((chunk, end_id))
396 })();
397 match result {
398 Ok((chunk, id)) => {
399 let _ = responder.send(Ok((&chunk[..], id)));
400 }
401 Err(e) => {
402 let _ = responder.send(Err(e));
403 return;
404 }
405 }
406 }
407 fsandbox::DictionaryDrainIteratorRequest::_UnknownMethod { ordinal, .. } => {
408 warn!(ordinal:%; "Unknown DictionaryDrainIterator request");
409 }
410 }
411 }
412}
413
414fn get_next_chunk(
415 store: &HashMap<u64, Capability>,
416 items: &mut impl Iterator<Item = (Key, Result<Capability, ()>)>,
417 next_id: &mut u64,
418 limit: u32,
419) -> Result<Vec<(Key, Option<(Capability, fsandbox::CapabilityId)>)>, fsandbox::CapabilityStoreError>
420{
421 if limit == 0 || limit > fsandbox::MAX_DICTIONARY_ITERATOR_CHUNK {
422 return Err(fsandbox::CapabilityStoreError::InvalidArgs);
423 }
424
425 let mut chunk = vec![];
426 for _ in 0..limit {
427 match items.next() {
428 Some((key, value)) => {
429 let value = match value {
430 Ok(value) => {
431 let id = *next_id;
432 if store.contains_key(&id) {
435 return Err(fsandbox::CapabilityStoreError::IdAlreadyExists);
436 }
437 *next_id += 1;
438 Some((value, id))
439 }
440 Err(_) => None,
441 };
442 chunk.push((key, value));
443 }
444 None => break,
445 }
446 }
447 Ok(chunk)
448}
449
450fn get_connector(
451 store: &HashMap<u64, Capability>,
452 id: u64,
453) -> Result<&Connector, fsandbox::CapabilityStoreError> {
454 let conn = store.get(&id).ok_or(fsandbox::CapabilityStoreError::IdNotFound)?;
455 if let Capability::Connector(conn) = conn {
456 Ok(conn)
457 } else {
458 Err(fsandbox::CapabilityStoreError::WrongType)
459 }
460}
461
462fn get_dir_connector(
463 store: &HashMap<u64, Capability>,
464 id: u64,
465) -> Result<&DirConnector, fsandbox::CapabilityStoreError> {
466 let conn = store.get(&id).ok_or(fsandbox::CapabilityStoreError::IdNotFound)?;
467 if let Capability::DirConnector(conn) = conn {
468 Ok(conn)
469 } else {
470 Err(fsandbox::CapabilityStoreError::WrongType)
471 }
472}
473
474fn get_dictionary(
475 store: &HashMap<u64, Capability>,
476 id: u64,
477) -> Result<&Dictionary, fsandbox::CapabilityStoreError> {
478 let dict = store.get(&id).ok_or(fsandbox::CapabilityStoreError::IdNotFound)?;
479 if let Capability::Dictionary(dict) = dict {
480 Ok(dict)
481 } else {
482 Err(fsandbox::CapabilityStoreError::WrongType)
483 }
484}
485
486fn insert_capability(
487 store: &mut HashMap<u64, Capability>,
488 id: u64,
489 cap: Capability,
490) -> Result<(), fsandbox::CapabilityStoreError> {
491 match store.entry(id) {
492 Entry::Occupied(_) => Err(fsandbox::CapabilityStoreError::IdAlreadyExists),
493 Entry::Vacant(entry) => {
494 entry.insert(cap);
495 Ok(())
496 }
497 }
498}
499
500async fn create_service_aggregate(
501 route_source: WeakInstanceToken,
502 sources: Vec<fsandbox::AggregateSource>,
503) -> Result<fsandbox::DirConnector, fsandbox::CapabilityStoreError> {
504 fn is_set<T>(val: &Option<Vec<T>>) -> bool {
505 val.as_ref().map(|v| !v.is_empty()).unwrap_or(false)
506 }
507 if sources.iter().any(|s| is_set(&s.source_instance_filter) || is_set(&s.renamed_instances)) {
508 let dir_connectors_and_renames = sources
510 .into_iter()
511 .map(|s| {
512 let renames = process_renames(&s);
513 let sandbox_dir_connector =
514 s.dir_connector.ok_or(fsandbox::CapabilityStoreError::InvalidArgs)?;
515 let dir_connector = DirConnector::try_from(sandbox_dir_connector)
516 .map_err(|_| fsandbox::CapabilityStoreError::InvalidArgs)?;
517 Ok((dir_connector, renames))
518 })
519 .collect::<Result<Vec<_>, fsandbox::CapabilityStoreError>>()?;
520 let target_directory = Simple::new();
521 for (dir_connector, renames) in dir_connectors_and_renames.into_iter() {
522 for mapping in renames.into_iter() {
523 let source_path = Path::validate_and_split(mapping.source_name)
524 .map_err(|_| fsandbox::CapabilityStoreError::InvalidArgs)?;
525 let target_path = Path::validate_and_split(mapping.target_name)
526 .map_err(|_| fsandbox::CapabilityStoreError::InvalidArgs)?;
527 let dir_connector_as_dir_entry = dir_connector
528 .clone()
529 .try_into_directory_entry(ExecutionScope::new(), route_source.clone())
530 .expect("this is infallible");
531 let sub_node = Arc::new(SubNode::new(
532 dir_connector_as_dir_entry,
533 source_path,
534 fio::DirentType::Directory,
535 ));
536 let sub_dir_connector =
537 DirConnector::from_directory_entry(sub_node, fio::PERM_READABLE);
538 let sub_dir_entry = sub_dir_connector
539 .try_into_directory_entry(ExecutionScope::new(), route_source.clone())
540 .expect("this is infallible");
541 target_directory
542 .add_entry(target_path.as_str(), sub_dir_entry)
543 .map_err(|_| fsandbox::CapabilityStoreError::InvalidArgs)?;
544 }
545 }
546 return Ok(DirConnector::from_directory_entry(target_directory, fio::PERM_READABLE).into());
547 }
548 Err(fsandbox::CapabilityStoreError::InvalidArgs)
550}
551
552fn process_renames(source: &fsandbox::AggregateSource) -> Vec<fdecl::NameMapping> {
553 match (&source.source_instance_filter, &source.renamed_instances) {
554 (Some(filter), Some(renames)) if !renames.is_empty() && !filter.is_empty() => renames
555 .iter()
556 .filter(|mapping| filter.contains(&mapping.target_name))
557 .cloned()
558 .collect(),
559 (Some(filter), _) if !filter.is_empty() => filter
560 .iter()
561 .map(|name| fdecl::NameMapping { source_name: name.clone(), target_name: name.clone() })
562 .collect(),
563 (_, Some(renames)) if !renames.is_empty() => renames.clone(),
564 _ => vec![],
565 }
566}
567
568#[cfg(test)]
569mod tests {
570 use super::*;
571 use crate::{Data, DirConnectable, Handle};
572 use assert_matches::assert_matches;
573 use fidl::endpoints::{ServerEnd, create_endpoints};
574 use fidl::{AsHandleRef, HandleBased, endpoints};
575 use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender, unbounded};
576
577 #[fuchsia::test]
578 async fn import_export() {
579 let (store, stream) =
580 endpoints::create_proxy_and_stream::<fsandbox::CapabilityStoreMarker>();
581 let _server = fasync::Task::spawn(async move {
582 let receiver_scope = fasync::Scope::new();
583 serve_capability_store(stream, &receiver_scope, WeakInstanceToken::new_invalid()).await
584 });
585
586 let (ch, _) = fidl::Channel::create();
587 let handle = ch.into_handle();
588 let handle_koid = handle.as_handle_ref().koid().unwrap();
589 let cap1 = Capability::Handle(Handle::new(handle));
590 let cap2 = Capability::Data(Data::Int64(42));
591 store
592 .import(1, cap1.into_fsandbox_capability(WeakInstanceToken::new_invalid()))
593 .await
594 .unwrap()
595 .unwrap();
596 store
597 .import(2, cap2.into_fsandbox_capability(WeakInstanceToken::new_invalid()))
598 .await
599 .unwrap()
600 .unwrap();
601
602 let cap1 = store.export(1).await.unwrap().unwrap();
603 let cap2 = store.export(2).await.unwrap().unwrap();
604 assert_matches!(
605 cap1,
606 fsandbox::Capability::Handle(h) if h.as_handle_ref().koid().unwrap() == handle_koid
607 );
608 assert_matches!(
609 cap2,
610 fsandbox::Capability::Data(fsandbox::Data::Int64(i)) if i == 42
611 );
612 }
613
614 #[fuchsia::test]
615 async fn import_error() {
616 let (store, stream) =
617 endpoints::create_proxy_and_stream::<fsandbox::CapabilityStoreMarker>();
618 let _server = fasync::Task::spawn(async move {
619 let receiver_scope = fasync::Scope::new();
620 serve_capability_store(stream, &receiver_scope, WeakInstanceToken::new_invalid()).await
621 });
622
623 let cap1 = Capability::Data(Data::Int64(42));
624 store
625 .import(1, cap1.clone().into_fsandbox_capability(WeakInstanceToken::new_invalid()))
626 .await
627 .unwrap()
628 .unwrap();
629 assert_matches!(
630 store
631 .import(1, cap1.into_fsandbox_capability(WeakInstanceToken::new_invalid()))
632 .await
633 .unwrap(),
634 Err(fsandbox::CapabilityStoreError::IdAlreadyExists)
635 );
636
637 let (token, _) = fidl::EventPair::create();
638 let bad_connector = fsandbox::Capability::Connector(fsandbox::Connector { token });
639 assert_matches!(
640 store.import(2, bad_connector).await.unwrap(),
641 Err(fsandbox::CapabilityStoreError::BadCapability)
642 );
643 }
644
645 #[fuchsia::test]
646 async fn export_error() {
647 let (store, stream) =
648 endpoints::create_proxy_and_stream::<fsandbox::CapabilityStoreMarker>();
649 let _server = fasync::Task::spawn(async move {
650 let receiver_scope = fasync::Scope::new();
651 serve_capability_store(stream, &receiver_scope, WeakInstanceToken::new_invalid()).await
652 });
653
654 let cap1 = Capability::Data(Data::Int64(42));
655 store
656 .import(1, cap1.clone().into_fsandbox_capability(WeakInstanceToken::new_invalid()))
657 .await
658 .unwrap()
659 .unwrap();
660
661 assert_matches!(
662 store.export(2).await.unwrap(),
663 Err(fsandbox::CapabilityStoreError::IdNotFound)
664 );
665 }
666
667 #[fuchsia::test]
668 async fn drop() {
669 let (store, stream) =
670 endpoints::create_proxy_and_stream::<fsandbox::CapabilityStoreMarker>();
671 let _server = fasync::Task::spawn(async move {
672 let receiver_scope = fasync::Scope::new();
673 serve_capability_store(stream, &receiver_scope, WeakInstanceToken::new_invalid()).await
674 });
675
676 let (ch, _) = fidl::Channel::create();
677 let handle = ch.into_handle();
678 let handle_koid = handle.as_handle_ref().koid().unwrap();
679 let cap1 = Capability::Handle(Handle::new(handle));
680 let cap2 = Capability::Data(Data::Int64(42));
681 store
682 .import(1, cap1.into_fsandbox_capability(WeakInstanceToken::new_invalid()))
683 .await
684 .unwrap()
685 .unwrap();
686 store
687 .import(2, cap2.into_fsandbox_capability(WeakInstanceToken::new_invalid()))
688 .await
689 .unwrap()
690 .unwrap();
691
692 store.drop(2).await.unwrap().unwrap();
694 assert_matches!(
695 store.export(1).await.unwrap(),
696 Ok(fsandbox::Capability::Handle(h)) if h.as_handle_ref().koid().unwrap() == handle_koid
697 );
698 assert_matches!(
699 store.export(2).await.unwrap(),
700 Err(fsandbox::CapabilityStoreError::IdNotFound)
701 );
702
703 let cap2 = Capability::Data(Data::Int64(84));
705 store
706 .import(2, cap2.into_fsandbox_capability(WeakInstanceToken::new_invalid()))
707 .await
708 .unwrap()
709 .unwrap();
710 assert_matches!(
711 store.export(2).await.unwrap(),
712 Ok(fsandbox::Capability::Data(fsandbox::Data::Int64(i))) if i == 84
713 );
714 }
715
716 #[fuchsia::test]
717 async fn drop_error() {
718 let (store, stream) =
719 endpoints::create_proxy_and_stream::<fsandbox::CapabilityStoreMarker>();
720 let _server = fasync::Task::spawn(async move {
721 let receiver_scope = fasync::Scope::new();
722 serve_capability_store(stream, &receiver_scope, WeakInstanceToken::new_invalid()).await
723 });
724
725 let cap1 = Capability::Data(Data::Int64(42));
726 store
727 .import(1, cap1.into_fsandbox_capability(WeakInstanceToken::new_invalid()))
728 .await
729 .unwrap()
730 .unwrap();
731
732 assert_matches!(
733 store.drop(2).await.unwrap(),
734 Err(fsandbox::CapabilityStoreError::IdNotFound)
735 );
736 }
737
738 #[fuchsia::test]
739 async fn duplicate() {
740 let (store, stream) =
741 endpoints::create_proxy_and_stream::<fsandbox::CapabilityStoreMarker>();
742 let _server = fasync::Task::spawn(async move {
743 let receiver_scope = fasync::Scope::new();
744 serve_capability_store(stream, &receiver_scope, WeakInstanceToken::new_invalid()).await
745 });
746
747 let (event, _) = fidl::EventPair::create();
748 let handle = event.into_handle();
749 let handle_koid = handle.as_handle_ref().koid().unwrap();
750 let cap1 = Capability::Handle(Handle::new(handle));
751 store
752 .import(1, cap1.into_fsandbox_capability(WeakInstanceToken::new_invalid()))
753 .await
754 .unwrap()
755 .unwrap();
756 store.duplicate(1, 2).await.unwrap().unwrap();
757 store.drop(1).await.unwrap().unwrap();
758
759 let cap1 = store.export(2).await.unwrap().unwrap();
760 assert_matches!(
761 cap1,
762 fsandbox::Capability::Handle(h) if h.as_handle_ref().koid().unwrap() == handle_koid
763 );
764 }
765
766 #[derive(Debug)]
767 struct TestDirConnector {
768 sender:
769 UnboundedSender<(ServerEnd<fio::DirectoryMarker>, RelativePath, Option<fio::Flags>)>,
770 }
771
772 impl DirConnectable for TestDirConnector {
773 fn maximum_flags(&self) -> fio::Flags {
774 fio::PERM_READABLE
775 }
776
777 fn send(
778 &self,
779 dir: ServerEnd<fio::DirectoryMarker>,
780 subdir: RelativePath,
781 flags: Option<fio::Flags>,
782 ) -> Result<(), ()> {
783 self.sender.unbounded_send((dir, subdir, flags)).unwrap();
784 Ok(())
785 }
786 }
787
788 impl TestDirConnector {
789 fn new() -> (
790 DirConnector,
791 UnboundedReceiver<(ServerEnd<fio::DirectoryMarker>, RelativePath, Option<fio::Flags>)>,
792 ) {
793 let (sender, receiver) = unbounded();
794 (DirConnector::new_sendable(Self { sender }), receiver)
795 }
796 }
797
798 #[fuchsia::test]
799 async fn rename_aggregate_with_one_source() {
800 let (source_dir_connector, mut source_dir_receiver) = TestDirConnector::new();
801 let sources = vec![fsandbox::AggregateSource {
802 dir_connector: Some(source_dir_connector.into()),
803 renamed_instances: Some(vec![fdecl::NameMapping {
804 source_name: "foo".to_string(),
805 target_name: "bar".to_string(),
806 }]),
807 ..Default::default()
808 }];
809 let fidl_aggregate = create_service_aggregate(WeakInstanceToken::new_invalid(), sources)
810 .await
811 .expect("failed to create service aggregate");
812 let aggregate = DirConnector::try_from(fidl_aggregate).expect("invalid dir connector");
813
814 let (client_end, server_end) = create_endpoints::<fio::DirectoryMarker>();
815 aggregate.send(server_end, RelativePath::new("bar").unwrap(), None).unwrap();
816 let (received_server_end, path, flags) = source_dir_receiver.try_next().unwrap().unwrap();
817 assert_eq!(
818 client_end.as_handle_ref().basic_info().unwrap().koid,
819 received_server_end.as_handle_ref().basic_info().unwrap().related_koid
820 );
821 assert_eq!(path, RelativePath::new("foo").unwrap());
822 assert_eq!(flags, Some(fio::PERM_READABLE));
823 }
824
825 #[fuchsia::test]
826 async fn rename_aggregate_with_two_sources() {
827 let (source_dir_connector_1, source_dir_receiver_1) = TestDirConnector::new();
828 let (source_dir_connector_2, source_dir_receiver_2) = TestDirConnector::new();
829 let sources = vec![
830 fsandbox::AggregateSource {
831 dir_connector: Some(source_dir_connector_1.into()),
832 renamed_instances: Some(vec![fdecl::NameMapping {
833 source_name: "foo".to_string(),
834 target_name: "bar".to_string(),
835 }]),
836 ..Default::default()
837 },
838 fsandbox::AggregateSource {
839 dir_connector: Some(source_dir_connector_2.into()),
840 renamed_instances: Some(vec![fdecl::NameMapping {
841 source_name: "foo".to_string(),
842 target_name: "baz".to_string(),
843 }]),
844 ..Default::default()
845 },
846 ];
847 let fidl_aggregate = create_service_aggregate(WeakInstanceToken::new_invalid(), sources)
848 .await
849 .expect("failed to create service aggregate");
850 let aggregate = DirConnector::try_from(fidl_aggregate).expect("invalid dir connector");
851
852 for (mut receiver, name) in [(source_dir_receiver_1, "bar"), (source_dir_receiver_2, "baz")]
853 {
854 let (client_end, server_end) = create_endpoints::<fio::DirectoryMarker>();
855 aggregate.send(server_end, RelativePath::new(name).unwrap(), None).unwrap();
856 let (received_server_end, path, flags) = receiver.try_next().unwrap().unwrap();
857 assert_eq!(
858 client_end.as_handle_ref().basic_info().unwrap().koid,
859 received_server_end.as_handle_ref().basic_info().unwrap().related_koid
860 );
861 assert_eq!(path, RelativePath::new("foo").unwrap());
862 assert_eq!(flags, Some(fio::PERM_READABLE));
863 }
864 }
865
866 #[fuchsia::test]
867 async fn rename_and_filtering_aggregate() {
868 let (source_dir_connector_1, source_dir_receiver_1) = TestDirConnector::new();
869 let (source_dir_connector_2, source_dir_receiver_2) = TestDirConnector::new();
870 let sources = vec![
871 fsandbox::AggregateSource {
872 dir_connector: Some(source_dir_connector_1.into()),
873 renamed_instances: Some(vec![fdecl::NameMapping {
874 source_name: "foo".to_string(),
875 target_name: "bar".to_string(),
876 }]),
877 ..Default::default()
878 },
879 fsandbox::AggregateSource {
880 dir_connector: Some(source_dir_connector_2.into()),
881 source_instance_filter: Some(vec!["foo".to_string()]),
882 ..Default::default()
883 },
884 ];
885 let fidl_aggregate = create_service_aggregate(WeakInstanceToken::new_invalid(), sources)
886 .await
887 .expect("failed to create service aggregate");
888 let aggregate = DirConnector::try_from(fidl_aggregate).expect("invalid dir connector");
889
890 for (mut receiver, name) in [(source_dir_receiver_1, "bar"), (source_dir_receiver_2, "foo")]
891 {
892 let (client_end, server_end) = create_endpoints::<fio::DirectoryMarker>();
893 aggregate.send(server_end, RelativePath::new(name).unwrap(), None).unwrap();
894 let (received_server_end, path, flags) = receiver.try_next().unwrap().unwrap();
895 assert_eq!(
896 client_end.as_handle_ref().basic_info().unwrap().koid,
897 received_server_end.as_handle_ref().basic_info().unwrap().related_koid
898 );
899 assert_eq!(path, RelativePath::new("foo").unwrap());
900 assert_eq!(flags, Some(fio::PERM_READABLE));
901 }
902 }
903}