1use crate::CapabilityBound;
6use std::fmt;
7
8#[derive(Clone)]
21pub struct DirEntry {
22 #[cfg(target_os = "fuchsia")]
23 pub(crate) entry: std::sync::Arc<dyn vfs::directory::entry::DirectoryEntry>,
24}
25
26impl CapabilityBound for DirEntry {
27 fn debug_typename() -> &'static str {
28 "DirEntry"
29 }
30}
31
32#[cfg(target_os = "fuchsia")]
33impl fmt::Debug for DirEntry {
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 f.debug_struct("DirEntry").field("entry_type", &self.entry.entry_info().type_()).finish()
36 }
37}
38
39#[cfg(not(target_os = "fuchsia"))]
40impl fmt::Debug for DirEntry {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 f.debug_struct("DirEntry").finish()
43 }
44}
45
46#[cfg(target_os = "fuchsia")]
47#[cfg(test)]
48mod tests {
49 use crate::fidl::RemotableCapability;
50 use crate::{Capability, Connector, Dict, DirEntry};
51 use assert_matches::assert_matches;
52 use fidl::endpoints::ClientEnd;
53 use fidl::{AsHandleRef, Channel};
54 use futures::StreamExt;
55 use vfs::directory::entry::OpenRequest;
56 use vfs::execution_scope::ExecutionScope;
57 use vfs::ToObjectRequest as _;
58 use zx::Status;
59 use {fidl_fuchsia_io as fio, fuchsia_async as fasync};
60
61 const FLAGS: fio::Flags = fio::Flags::PROTOCOL_SERVICE;
62
63 #[fuchsia::test]
64 async fn test_connector_into_open() {
65 let (receiver, sender) = Connector::new();
66 let scope = ExecutionScope::new();
67 let dir_entry = DirEntry::new(sender.try_into_directory_entry(scope.clone()).unwrap());
68 let (client_end, server_end) = Channel::create();
69 FLAGS.to_object_request(server_end).handle(|request| {
70 dir_entry.open_entry(OpenRequest::new(scope, FLAGS, vfs::Path::dot(), request))
71 });
72 let msg = receiver.receive().await.unwrap();
73 assert_eq!(
74 client_end.basic_info().unwrap().related_koid,
75 msg.channel.basic_info().unwrap().koid
76 );
77 }
78
79 #[test]
80 fn test_connector_into_open_extra_path() {
81 let mut ex = fasync::TestExecutor::new();
82
83 let (receiver, sender) = Connector::new();
84 let scope = ExecutionScope::new();
85 let dir_entry = DirEntry::new(sender.try_into_directory_entry(scope.clone()).unwrap());
86 let (client_end, server_end) = Channel::create();
87 let path = vfs::Path::validate_and_split("foo").unwrap();
88 FLAGS
89 .to_object_request(server_end)
90 .handle(|request| dir_entry.open_entry(OpenRequest::new(scope, FLAGS, path, request)));
91
92 let mut fut = std::pin::pin!(receiver.receive());
93 assert!(ex.run_until_stalled(&mut fut).is_pending());
94
95 let client_end: ClientEnd<fio::NodeMarker> = client_end.into();
96 let node: fio::NodeProxy = client_end.into_proxy();
97 let result = ex.run_singlethreaded(node.take_event_stream().next()).unwrap();
98 assert_matches!(
99 result,
100 Err(fidl::Error::ClientChannelClosed { status, .. })
101 if status == Status::NOT_DIR
102 );
103 }
104
105 #[fuchsia::test]
106 async fn test_connector_into_open_via_dict() {
107 let dict = Dict::new();
108 let (receiver, sender) = Connector::new();
109 dict.insert("echo".parse().unwrap(), Capability::Connector(sender))
110 .expect("dict entry already exists");
111
112 let scope = ExecutionScope::new();
113 let dir_entry = DirEntry::new(dict.try_into_directory_entry(scope.clone()).unwrap());
114 let (client_end, server_end) = Channel::create();
115 let path = vfs::Path::validate_and_split("echo").unwrap();
116 FLAGS
117 .to_object_request(server_end)
118 .handle(|request| dir_entry.open_entry(OpenRequest::new(scope, FLAGS, path, request)));
119
120 let msg = receiver.receive().await.unwrap();
121 assert_eq!(
122 client_end.basic_info().unwrap().related_koid,
123 msg.channel.basic_info().unwrap().koid
124 );
125 }
126
127 #[test]
128 fn test_connector_into_open_via_dict_extra_path() {
129 let mut ex = fasync::TestExecutor::new();
130
131 let dict = Dict::new();
132 let (receiver, sender) = Connector::new();
133 dict.insert("echo".parse().unwrap(), Capability::Connector(sender))
134 .expect("dict entry already exists");
135
136 let scope = ExecutionScope::new();
137 let dir_entry = DirEntry::new(dict.try_into_directory_entry(scope.clone()).unwrap());
138 let (client_end, server_end) = Channel::create();
139 let path = vfs::Path::validate_and_split("echo/foo").unwrap();
140 FLAGS
141 .to_object_request(server_end)
142 .handle(|request| dir_entry.open_entry(OpenRequest::new(scope, FLAGS, path, request)));
143
144 let mut fut = std::pin::pin!(receiver.receive());
145 assert!(ex.run_until_stalled(&mut fut).is_pending());
146
147 let client_end: ClientEnd<fio::NodeMarker> = client_end.into();
148 let node: fio::NodeProxy = client_end.into_proxy();
149 let result = ex.run_singlethreaded(node.take_event_stream().next()).unwrap();
150 assert_matches!(
151 result,
152 Err(fidl::Error::ClientChannelClosed { status, .. })
153 if status == Status::NOT_DIR
154 );
155 }
156}