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