1use crate::common::IntoAny;
8use crate::directory::entry::GetEntryInfo;
9use crate::directory::entry_container::MutableDirectory;
10use crate::execution_scope::ExecutionScope;
11use crate::name::Name;
12use crate::object_request::{ConnectionCreator, Representation, run_synchronous_future_or_spawn};
13use crate::protocols::ToNodeOptions;
14use crate::request_handler::{RequestHandler, RequestListener};
15use crate::{ObjectRequest, ObjectRequestRef};
16use anyhow::Error;
17use fidl::endpoints::{DiscoverableProtocolMarker as _, ServerEnd};
18use fidl_fuchsia_io as fio;
19use libc::{S_IRUSR, S_IWUSR};
20use std::future::{Future, ready};
21use std::ops::ControlFlow;
22use std::pin::Pin;
23use std::sync::Arc;
24use zx_status::Status;
25
26#[cfg(not(target_os = "macos"))]
28pub const POSIX_READ_WRITE_PROTECTION_ATTRIBUTES: u32 = S_IRUSR | S_IWUSR;
29#[cfg(target_os = "macos")]
30pub const POSIX_READ_WRITE_PROTECTION_ATTRIBUTES: u16 = S_IRUSR | S_IWUSR;
31
32#[derive(Clone, Copy)]
33pub struct NodeOptions {
34 pub rights: fio::Operations,
35}
36
37impl From<&NodeOptions> for fio::Flags {
38 fn from(options: &NodeOptions) -> Self {
39 fio::Flags::PROTOCOL_NODE | fio::Flags::from_bits_truncate(options.rights.bits())
41 }
42}
43
44pub trait Node: GetEntryInfo + IntoAny + Send + Sync + 'static {
46 fn get_attributes(
48 &self,
49 requested_attributes: fio::NodeAttributesQuery,
50 ) -> impl Future<Output = Result<fio::NodeAttributes2, Status>> + Send
51 where
52 Self: Sized;
53
54 fn will_open_as_node(&self) -> Result<(), Status> {
58 self.will_clone();
59 Ok(())
60 }
61
62 fn will_clone(&self) {}
66
67 fn close(self: Arc<Self>) {}
69
70 fn link_into(
71 self: Arc<Self>,
72 _destination_dir: Arc<dyn MutableDirectory>,
73 _name: Name,
74 ) -> impl Future<Output = Result<(), Status>> + Send
75 where
76 Self: Sized,
77 {
78 ready(Err(Status::NOT_SUPPORTED))
79 }
80
81 fn query_filesystem(&self) -> Result<fio::FilesystemInfo, Status> {
83 Err(Status::NOT_SUPPORTED)
84 }
85
86 fn open_as_node(
88 self: Arc<Self>,
89 scope: ExecutionScope,
90 options: NodeOptions,
91 object_request: ObjectRequestRef<'_>,
92 ) -> Result<(), Status>
93 where
94 Self: Sized,
95 {
96 self.will_open_as_node()?;
97 Connection::create_sync(scope, self, options, object_request.take());
98 Ok(())
99 }
100
101 fn list_extended_attributes(&self) -> impl Future<Output = Result<Vec<Vec<u8>>, Status>> + Send
103 where
104 Self: Sized,
105 {
106 ready(Err(Status::NOT_SUPPORTED))
107 }
108
109 fn get_extended_attribute(
111 &self,
112 _name: Vec<u8>,
113 ) -> impl Future<Output = Result<Vec<u8>, Status>> + Send
114 where
115 Self: Sized,
116 {
117 ready(Err(Status::NOT_SUPPORTED))
118 }
119
120 fn set_extended_attribute(
122 &self,
123 _name: Vec<u8>,
124 _value: Vec<u8>,
125 _mode: fio::SetExtendedAttributeMode,
126 ) -> impl Future<Output = Result<(), Status>> + Send
127 where
128 Self: Sized,
129 {
130 ready(Err(Status::NOT_SUPPORTED))
131 }
132
133 fn remove_extended_attribute(
135 &self,
136 _name: Vec<u8>,
137 ) -> impl Future<Output = Result<(), Status>> + Send
138 where
139 Self: Sized,
140 {
141 ready(Err(Status::NOT_SUPPORTED))
142 }
143}
144
145pub struct Connection<N: Node> {
147 scope: ExecutionScope,
150
151 node: OpenNode<N>,
153
154 options: NodeOptions,
156}
157
158enum ConnectionState {
160 Alive,
162 Closed,
166}
167
168impl<N: Node> Connection<N> {
169 pub async fn create(
175 scope: ExecutionScope,
176 node: Arc<N>,
177 options: impl ToNodeOptions,
178 object_request: ObjectRequestRef<'_>,
179 ) -> Result<(), Status> {
180 let node = OpenNode::new(node);
181 let options = options.to_node_options(node.entry_info().type_())?;
182 let connection = Connection { scope: scope.clone(), node, options };
183 if let Ok(requests) = object_request.take().into_request_stream(&connection).await {
184 scope.spawn(RequestListener::new(requests, connection));
185 }
186 Ok(())
187 }
188
189 pub fn create_sync(
192 scope: ExecutionScope,
193 node: Arc<N>,
194 options: impl ToNodeOptions,
195 object_request: ObjectRequest,
196 ) {
197 run_synchronous_future_or_spawn(
198 scope.clone(),
199 object_request.handle_async(async |object_request| {
200 Self::create(scope, node, options, object_request).await
201 }),
202 )
203 }
204
205 async fn handle_request(&mut self, req: fio::NodeRequest) -> Result<ConnectionState, Error> {
207 match req {
208 #[cfg(any(
209 fuchsia_api_level_at_least = "PLATFORM",
210 not(fuchsia_api_level_at_least = "29")
211 ))]
212 fio::NodeRequest::DeprecatedClone { flags, object, control_handle: _ } => {
213 crate::common::send_on_open_with_error(
214 flags.contains(fio::OpenFlags::DESCRIBE),
215 object,
216 Status::NOT_SUPPORTED,
217 );
218 }
219 fio::NodeRequest::Clone { request, control_handle: _ } => {
220 self.handle_clone(ServerEnd::new(request.into_channel()));
222 }
223 fio::NodeRequest::Close { responder } => {
224 responder.send(Ok(()))?;
225 return Ok(ConnectionState::Closed);
226 }
227 fio::NodeRequest::Sync { responder } => {
228 responder.send(Err(Status::NOT_SUPPORTED.into_raw()))?;
229 }
230 #[cfg(fuchsia_api_level_at_least = "28")]
231 fio::NodeRequest::DeprecatedGetAttr { responder } => {
232 let (status, attrs) =
233 crate::common::io2_to_io1_attrs(self.node.as_ref(), self.options.rights).await;
234 responder.send(status.into_raw(), &attrs)?;
235 }
236 #[cfg(not(fuchsia_api_level_at_least = "28"))]
237 fio::NodeRequest::GetAttr { responder } => {
238 let (status, attrs) =
239 crate::common::io2_to_io1_attrs(self.node.as_ref(), self.options.rights).await;
240 responder.send(status.into_raw(), &attrs)?;
241 }
242 #[cfg(fuchsia_api_level_at_least = "28")]
243 fio::NodeRequest::DeprecatedSetAttr { flags: _, attributes: _, responder } => {
244 responder.send(Status::BAD_HANDLE.into_raw())?;
245 }
246 #[cfg(not(fuchsia_api_level_at_least = "28"))]
247 fio::NodeRequest::SetAttr { flags: _, attributes: _, responder } => {
248 responder.send(Status::BAD_HANDLE.into_raw())?;
249 }
250 fio::NodeRequest::GetAttributes { query, responder } => {
251 let result = self.node.get_attributes(query).await;
252 responder.send(
253 result
254 .as_ref()
255 .map(|attrs| (&attrs.mutable_attributes, &attrs.immutable_attributes))
256 .map_err(|status| status.into_raw()),
257 )?;
258 }
259 fio::NodeRequest::UpdateAttributes { payload: _, responder } => {
260 responder.send(Err(Status::BAD_HANDLE.into_raw()))?;
261 }
262 fio::NodeRequest::ListExtendedAttributes { iterator, .. } => {
263 iterator.close_with_epitaph(Status::NOT_SUPPORTED)?;
264 }
265 fio::NodeRequest::GetExtendedAttribute { responder, .. } => {
266 responder.send(Err(Status::NOT_SUPPORTED.into_raw()))?;
267 }
268 fio::NodeRequest::SetExtendedAttribute { responder, .. } => {
269 responder.send(Err(Status::NOT_SUPPORTED.into_raw()))?;
270 }
271 fio::NodeRequest::RemoveExtendedAttribute { responder, .. } => {
272 responder.send(Err(Status::NOT_SUPPORTED.into_raw()))?;
273 }
274 fio::NodeRequest::GetFlags { responder } => {
275 responder.send(Ok(fio::Flags::from(&self.options)))?;
276 }
277 fio::NodeRequest::SetFlags { flags: _, responder } => {
278 responder.send(Err(Status::NOT_SUPPORTED.into_raw()))?;
279 }
280 fio::NodeRequest::DeprecatedGetFlags { responder } => {
281 responder.send(Status::OK.into_raw(), fio::OpenFlags::NODE_REFERENCE)?;
282 }
283 fio::NodeRequest::DeprecatedSetFlags { flags: _, responder } => {
284 responder.send(Status::BAD_HANDLE.into_raw())?;
285 }
286 fio::NodeRequest::Query { responder } => {
287 responder.send(fio::NodeMarker::PROTOCOL_NAME.as_bytes())?;
288 }
289 fio::NodeRequest::QueryFilesystem { responder } => {
290 responder.send(Status::NOT_SUPPORTED.into_raw(), None)?;
291 }
292 fio::NodeRequest::_UnknownMethod { .. } => (),
293 }
294 Ok(ConnectionState::Alive)
295 }
296
297 fn handle_clone(&mut self, server_end: ServerEnd<fio::NodeMarker>) {
298 self.node.will_clone();
299 let connection = Self {
300 scope: self.scope.clone(),
301 node: OpenNode::new(self.node.clone()),
302 options: self.options,
303 };
304 self.scope.spawn(RequestListener::new(server_end.into_stream(), connection));
305 }
306}
307
308impl<N: Node> RequestHandler for Connection<N> {
309 type Request = Result<fio::NodeRequest, fidl::Error>;
310
311 async fn handle_request(self: Pin<&mut Self>, request: Self::Request) -> ControlFlow<()> {
312 let this = self.get_mut();
313 if let Some(_guard) = this.scope.try_active_guard() {
314 match request {
315 Ok(request) => match this.handle_request(request).await {
316 Ok(ConnectionState::Alive) => ControlFlow::Continue(()),
317 Ok(ConnectionState::Closed) | Err(_) => ControlFlow::Break(()),
318 },
319 Err(_) => ControlFlow::Break(()),
320 }
321 } else {
322 ControlFlow::Break(())
323 }
324 }
325}
326
327impl<N: Node> Representation for Connection<N> {
328 type Protocol = fio::NodeMarker;
329
330 async fn get_representation(
331 &self,
332 requested_attributes: fio::NodeAttributesQuery,
333 ) -> Result<fio::Representation, Status> {
334 Ok(fio::Representation::Node(fio::NodeInfo {
335 attributes: if requested_attributes.is_empty() {
336 None
337 } else {
338 Some(self.node.get_attributes(requested_attributes).await?)
339 },
340 ..Default::default()
341 }))
342 }
343
344 async fn node_info(&self) -> Result<fio::NodeInfoDeprecated, Status> {
345 Ok(fio::NodeInfoDeprecated::Service(fio::Service))
346 }
347}
348
349impl<N: Node> ConnectionCreator<N> for Connection<N> {
350 async fn create<'a>(
351 scope: ExecutionScope,
352 node: Arc<N>,
353 protocols: impl crate::ProtocolsExt,
354 object_request: ObjectRequestRef<'a>,
355 ) -> Result<(), Status> {
356 Self::create(scope, node, protocols, object_request).await
357 }
358}
359
360pub struct OpenNode<T: Node> {
362 node: Arc<T>,
363}
364
365impl<T: Node> OpenNode<T> {
366 pub fn new(node: Arc<T>) -> Self {
367 Self { node }
368 }
369}
370
371impl<T: Node> Drop for OpenNode<T> {
372 fn drop(&mut self) {
373 self.node.clone().close();
374 }
375}
376
377impl<T: Node> std::ops::Deref for OpenNode<T> {
378 type Target = Arc<T>;
379
380 fn deref(&self) -> &Self::Target {
381 &self.node
382 }
383}