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 #[cfg(fuchsia_api_level_at_least = "27")]
275 fio::NodeRequest::GetFlags { responder } => {
276 responder.send(Ok(fio::Flags::from(&self.options)))?;
277 }
278 #[cfg(fuchsia_api_level_at_least = "27")]
279 fio::NodeRequest::SetFlags { flags: _, responder } => {
280 responder.send(Err(Status::NOT_SUPPORTED.into_raw()))?;
281 }
282 #[cfg(fuchsia_api_level_at_least = "27")]
283 fio::NodeRequest::DeprecatedGetFlags { responder } => {
284 responder.send(Status::OK.into_raw(), fio::OpenFlags::NODE_REFERENCE)?;
285 }
286 #[cfg(fuchsia_api_level_at_least = "27")]
287 fio::NodeRequest::DeprecatedSetFlags { flags: _, responder } => {
288 responder.send(Status::BAD_HANDLE.into_raw())?;
289 }
290 #[cfg(not(fuchsia_api_level_at_least = "27"))]
291 fio::NodeRequest::GetFlags { responder } => {
292 responder.send(Status::OK.into_raw(), fio::OpenFlags::NODE_REFERENCE)?;
293 }
294 #[cfg(not(fuchsia_api_level_at_least = "27"))]
295 fio::NodeRequest::SetFlags { flags: _, responder } => {
296 responder.send(Status::BAD_HANDLE.into_raw())?;
297 }
298 fio::NodeRequest::Query { responder } => {
299 responder.send(fio::NodeMarker::PROTOCOL_NAME.as_bytes())?;
300 }
301 fio::NodeRequest::QueryFilesystem { responder } => {
302 responder.send(Status::NOT_SUPPORTED.into_raw(), None)?;
303 }
304 fio::NodeRequest::_UnknownMethod { .. } => (),
305 }
306 Ok(ConnectionState::Alive)
307 }
308
309 fn handle_clone(&mut self, server_end: ServerEnd<fio::NodeMarker>) {
310 self.node.will_clone();
311 let connection = Self {
312 scope: self.scope.clone(),
313 node: OpenNode::new(self.node.clone()),
314 options: self.options,
315 };
316 self.scope.spawn(RequestListener::new(server_end.into_stream(), connection));
317 }
318}
319
320impl<N: Node> RequestHandler for Connection<N> {
321 type Request = Result<fio::NodeRequest, fidl::Error>;
322
323 async fn handle_request(self: Pin<&mut Self>, request: Self::Request) -> ControlFlow<()> {
324 let this = self.get_mut();
325 if let Some(_guard) = this.scope.try_active_guard() {
326 match request {
327 Ok(request) => match this.handle_request(request).await {
328 Ok(ConnectionState::Alive) => ControlFlow::Continue(()),
329 Ok(ConnectionState::Closed) | Err(_) => ControlFlow::Break(()),
330 },
331 Err(_) => ControlFlow::Break(()),
332 }
333 } else {
334 ControlFlow::Break(())
335 }
336 }
337}
338
339impl<N: Node> Representation for Connection<N> {
340 type Protocol = fio::NodeMarker;
341
342 #[cfg(fuchsia_api_level_at_least = "27")]
343 async fn get_representation(
344 &self,
345 requested_attributes: fio::NodeAttributesQuery,
346 ) -> Result<fio::Representation, Status> {
347 Ok(fio::Representation::Node(fio::NodeInfo {
348 attributes: if requested_attributes.is_empty() {
349 None
350 } else {
351 Some(self.node.get_attributes(requested_attributes).await?)
352 },
353 ..Default::default()
354 }))
355 }
356
357 #[cfg(not(fuchsia_api_level_at_least = "27"))]
358 async fn get_representation(
359 &self,
360 requested_attributes: fio::NodeAttributesQuery,
361 ) -> Result<fio::Representation, Status> {
362 Ok(fio::Representation::Connector(fio::ConnectorInfo {
363 attributes: if requested_attributes.is_empty() {
364 None
365 } else {
366 Some(self.node.get_attributes(requested_attributes).await?)
367 },
368 ..Default::default()
369 }))
370 }
371
372 async fn node_info(&self) -> Result<fio::NodeInfoDeprecated, Status> {
373 Ok(fio::NodeInfoDeprecated::Service(fio::Service))
374 }
375}
376
377impl<N: Node> ConnectionCreator<N> for Connection<N> {
378 async fn create<'a>(
379 scope: ExecutionScope,
380 node: Arc<N>,
381 protocols: impl crate::ProtocolsExt,
382 object_request: ObjectRequestRef<'a>,
383 ) -> Result<(), Status> {
384 Self::create(scope, node, protocols, object_request).await
385 }
386}
387
388pub struct OpenNode<T: Node> {
390 node: Arc<T>,
391}
392
393impl<T: Node> OpenNode<T> {
394 pub fn new(node: Arc<T>) -> Self {
395 Self { node }
396 }
397}
398
399impl<T: Node> Drop for OpenNode<T> {
400 fn drop(&mut self) {
401 self.node.clone().close();
402 }
403}
404
405impl<T: Node> std::ops::Deref for OpenNode<T> {
406 type Target = Arc<T>;
407
408 fn deref(&self) -> &Self::Target {
409 &self.node
410 }
411}