1use crate::common::{inherit_rights_for_clone, 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::{run_synchronous_future_or_spawn, ConnectionCreator, Representation};
13use crate::protocols::ToNodeOptions;
14use crate::request_handler::{RequestHandler, RequestListener};
15use crate::{ObjectRequest, ObjectRequestRef, ToObjectRequest};
16use anyhow::Error;
17use fidl::endpoints::ServerEnd;
18use fidl_fuchsia_io as fio;
19use libc::{S_IRUSR, S_IWUSR};
20use std::future::{ready, Future};
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
102pub struct Connection<N: Node> {
104 scope: ExecutionScope,
107
108 node: OpenNode<N>,
110
111 options: NodeOptions,
113}
114
115enum ConnectionState {
117 Alive,
119 Closed,
123}
124
125impl<N: Node> Connection<N> {
126 pub async fn create(
132 scope: ExecutionScope,
133 node: Arc<N>,
134 options: impl ToNodeOptions,
135 object_request: ObjectRequestRef<'_>,
136 ) -> Result<(), Status> {
137 let node = OpenNode::new(node);
138 let options = options.to_node_options(node.entry_info().type_())?;
139 let connection = Connection { scope: scope.clone(), node, options };
140 if let Ok(requests) = object_request.take().into_request_stream(&connection).await {
141 scope.spawn(RequestListener::new(requests, connection));
142 }
143 Ok(())
144 }
145
146 pub fn create_sync(
149 scope: ExecutionScope,
150 node: Arc<N>,
151 options: impl ToNodeOptions,
152 object_request: ObjectRequest,
153 ) {
154 run_synchronous_future_or_spawn(
155 scope.clone(),
156 object_request.handle_async(async |object_request| {
157 Self::create(scope, node, options, object_request).await
158 }),
159 )
160 }
161
162 async fn handle_request(&mut self, req: fio::NodeRequest) -> Result<ConnectionState, Error> {
164 match req {
165 #[cfg(fuchsia_api_level_at_least = "26")]
166 fio::NodeRequest::DeprecatedClone { flags, object, control_handle: _ } => {
167 self.handle_clone_deprecated(flags, object).await;
168 }
169 #[cfg(not(fuchsia_api_level_at_least = "26"))]
170 fio::NodeRequest::Clone { flags, object, control_handle: _ } => {
171 self.handle_clone_deprecated(flags, object).await;
172 }
173 #[cfg(fuchsia_api_level_at_least = "26")]
174 fio::NodeRequest::Clone { request, control_handle: _ } => {
175 self.handle_clone(ServerEnd::new(request.into_channel()));
177 }
178 #[cfg(not(fuchsia_api_level_at_least = "26"))]
179 fio::NodeRequest::Clone2 { request, control_handle: _ } => {
180 self.handle_clone(ServerEnd::new(request.into_channel()));
182 }
183 fio::NodeRequest::Close { responder } => {
184 responder.send(Ok(()))?;
185 return Ok(ConnectionState::Closed);
186 }
187 fio::NodeRequest::Sync { responder } => {
188 responder.send(Err(Status::NOT_SUPPORTED.into_raw()))?;
189 }
190 #[cfg(fuchsia_api_level_at_least = "NEXT")]
191 fio::NodeRequest::DeprecatedGetAttr { responder } => {
192 let (status, attrs) =
193 crate::common::io2_to_io1_attrs(self.node.as_ref(), self.options.rights).await;
194 responder.send(status.into_raw(), &attrs)?;
195 }
196 #[cfg(not(fuchsia_api_level_at_least = "NEXT"))]
197 fio::NodeRequest::GetAttr { responder } => {
198 let (status, attrs) =
199 crate::common::io2_to_io1_attrs(self.node.as_ref(), self.options.rights).await;
200 responder.send(status.into_raw(), &attrs)?;
201 }
202 #[cfg(fuchsia_api_level_at_least = "NEXT")]
203 fio::NodeRequest::DeprecatedSetAttr { flags: _, attributes: _, responder } => {
204 responder.send(Status::BAD_HANDLE.into_raw())?;
205 }
206 #[cfg(not(fuchsia_api_level_at_least = "NEXT"))]
207 fio::NodeRequest::SetAttr { flags: _, attributes: _, responder } => {
208 responder.send(Status::BAD_HANDLE.into_raw())?;
209 }
210 fio::NodeRequest::GetAttributes { query, responder } => {
211 let result = self.node.get_attributes(query).await;
212 responder.send(
213 result
214 .as_ref()
215 .map(|attrs| (&attrs.mutable_attributes, &attrs.immutable_attributes))
216 .map_err(|status| status.into_raw()),
217 )?;
218 }
219 fio::NodeRequest::UpdateAttributes { payload: _, responder } => {
220 responder.send(Err(Status::BAD_HANDLE.into_raw()))?;
221 }
222 fio::NodeRequest::ListExtendedAttributes { iterator, .. } => {
223 iterator.close_with_epitaph(Status::NOT_SUPPORTED)?;
224 }
225 fio::NodeRequest::GetExtendedAttribute { responder, .. } => {
226 responder.send(Err(Status::NOT_SUPPORTED.into_raw()))?;
227 }
228 fio::NodeRequest::SetExtendedAttribute { responder, .. } => {
229 responder.send(Err(Status::NOT_SUPPORTED.into_raw()))?;
230 }
231 fio::NodeRequest::RemoveExtendedAttribute { responder, .. } => {
232 responder.send(Err(Status::NOT_SUPPORTED.into_raw()))?;
233 }
234 #[cfg(fuchsia_api_level_at_least = "27")]
235 fio::NodeRequest::GetFlags { responder } => {
236 responder.send(Ok(fio::Flags::from(&self.options)))?;
237 }
238 #[cfg(fuchsia_api_level_at_least = "27")]
239 fio::NodeRequest::SetFlags { flags: _, responder } => {
240 responder.send(Err(Status::NOT_SUPPORTED.into_raw()))?;
241 }
242 #[cfg(fuchsia_api_level_at_least = "27")]
243 fio::NodeRequest::DeprecatedGetFlags { responder } => {
244 responder.send(Status::OK.into_raw(), fio::OpenFlags::NODE_REFERENCE)?;
245 }
246 #[cfg(fuchsia_api_level_at_least = "27")]
247 fio::NodeRequest::DeprecatedSetFlags { flags: _, responder } => {
248 responder.send(Status::BAD_HANDLE.into_raw())?;
249 }
250 #[cfg(not(fuchsia_api_level_at_least = "27"))]
251 fio::NodeRequest::GetFlags { responder } => {
252 responder.send(Status::OK.into_raw(), fio::OpenFlags::NODE_REFERENCE)?;
253 }
254 #[cfg(not(fuchsia_api_level_at_least = "27"))]
255 fio::NodeRequest::SetFlags { flags: _, responder } => {
256 responder.send(Status::BAD_HANDLE.into_raw())?;
257 }
258 fio::NodeRequest::Query { responder } => {
259 responder.send(fio::NODE_PROTOCOL_NAME.as_bytes())?;
260 }
261 fio::NodeRequest::QueryFilesystem { responder } => {
262 responder.send(Status::NOT_SUPPORTED.into_raw(), None)?;
263 }
264 fio::NodeRequest::_UnknownMethod { .. } => (),
265 }
266 Ok(ConnectionState::Alive)
267 }
268
269 async fn handle_clone_deprecated(
270 &mut self,
271 flags: fio::OpenFlags,
272 server_end: ServerEnd<fio::NodeMarker>,
273 ) {
274 flags
275 .to_object_request(server_end)
276 .handle_async(async |object_request| {
277 let options = inherit_rights_for_clone(fio::OpenFlags::NODE_REFERENCE, flags)?
278 .to_node_options(self.node.entry_info().type_())?;
279
280 self.node.will_clone();
281
282 let connection = Self {
283 scope: self.scope.clone(),
284 node: OpenNode::new(self.node.clone()),
285 options,
286 };
287
288 let requests = object_request.take().into_request_stream(&connection).await?;
289 self.scope.spawn(RequestListener::new(requests, connection));
290
291 Ok(())
292 })
293 .await;
294 }
295
296 fn handle_clone(&mut self, server_end: ServerEnd<fio::NodeMarker>) {
297 self.node.will_clone();
298 let connection = Self {
299 scope: self.scope.clone(),
300 node: OpenNode::new(self.node.clone()),
301 options: self.options,
302 };
303 self.scope.spawn(RequestListener::new(server_end.into_stream(), connection));
304 }
305}
306
307impl<N: Node> RequestHandler for Connection<N> {
308 type Request = Result<fio::NodeRequest, fidl::Error>;
309
310 async fn handle_request(self: Pin<&mut Self>, request: Self::Request) -> ControlFlow<()> {
311 let this = self.get_mut();
312 if let Some(_guard) = this.scope.try_active_guard() {
313 match request {
314 Ok(request) => match this.handle_request(request).await {
315 Ok(ConnectionState::Alive) => ControlFlow::Continue(()),
316 Ok(ConnectionState::Closed) | Err(_) => ControlFlow::Break(()),
317 },
318 Err(_) => ControlFlow::Break(()),
319 }
320 } else {
321 ControlFlow::Break(())
322 }
323 }
324}
325
326impl<N: Node> Representation for Connection<N> {
327 type Protocol = fio::NodeMarker;
328
329 #[cfg(fuchsia_api_level_at_least = "27")]
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 #[cfg(not(fuchsia_api_level_at_least = "27"))]
345 async fn get_representation(
346 &self,
347 requested_attributes: fio::NodeAttributesQuery,
348 ) -> Result<fio::Representation, Status> {
349 Ok(fio::Representation::Connector(fio::ConnectorInfo {
350 attributes: if requested_attributes.is_empty() {
351 None
352 } else {
353 Some(self.node.get_attributes(requested_attributes).await?)
354 },
355 ..Default::default()
356 }))
357 }
358
359 async fn node_info(&self) -> Result<fio::NodeInfoDeprecated, Status> {
360 Ok(fio::NodeInfoDeprecated::Service(fio::Service))
361 }
362}
363
364impl<N: Node> ConnectionCreator<N> for Connection<N> {
365 async fn create<'a>(
366 scope: ExecutionScope,
367 node: Arc<N>,
368 protocols: impl crate::ProtocolsExt,
369 object_request: ObjectRequestRef<'a>,
370 ) -> Result<(), Status> {
371 Self::create(scope, node, protocols, object_request).await
372 }
373}
374
375pub struct OpenNode<T: Node> {
377 node: Arc<T>,
378}
379
380impl<T: Node> OpenNode<T> {
381 pub fn new(node: Arc<T>) -> Self {
382 Self { node }
383 }
384}
385
386impl<T: Node> Drop for OpenNode<T> {
387 fn drop(&mut self) {
388 self.node.clone().close();
389 }
390}
391
392impl<T: Node> std::ops::Deref for OpenNode<T> {
393 type Target = Arc<T>;
394
395 fn deref(&self) -> &Self::Target {
396 &self.node
397 }
398}