1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
45//! `EntryContainer` is a trait implemented by directories that allow manipulation of their
6//! content.
78use crate::directory::dirents_sink;
9use crate::directory::traversal_position::TraversalPosition;
10use crate::execution_scope::ExecutionScope;
11use crate::node::Node;
12use crate::object_request::{ObjectRequestRef, ToObjectRequest as _};
13use crate::path::Path;
14use fidl::endpoints::ServerEnd;
15use fidl_fuchsia_io as fio;
16use futures::future::BoxFuture;
17use std::any::Any;
18use std::future::{ready, Future};
19use std::sync::Arc;
20use zx_status::Status;
2122mod private {
23use fidl_fuchsia_io as fio;
2425/// A type-preserving wrapper around [`fuchsia_async::Channel`].
26#[derive(Debug)]
27pub struct DirectoryWatcher {
28 channel: fuchsia_async::Channel,
29 }
3031impl DirectoryWatcher {
32/// Provides access to the underlying channel.
33pub fn channel(&self) -> &fuchsia_async::Channel {
34let Self { channel } = self;
35 channel
36 }
37 }
3839impl TryFrom<fidl::endpoints::ServerEnd<fio::DirectoryWatcherMarker>> for DirectoryWatcher {
40type Error = zx_status::Status;
4142fn try_from(
43 server_end: fidl::endpoints::ServerEnd<fio::DirectoryWatcherMarker>,
44 ) -> Result<Self, Self::Error> {
45let channel = fuchsia_async::Channel::from_channel(server_end.into_channel());
46Ok(Self { channel })
47 }
48 }
49}
5051pub use private::DirectoryWatcher;
5253/// All directories implement this trait. If a directory can be modified it should
54/// also implement the `MutableDirectory` trait.
55pub trait Directory: Node {
56/// Opens a connection to this item if the `path` is "." or a connection to an item inside
57 /// this one otherwise. `path` will not contain any "." or ".." components.
58 ///
59 /// `flags` corresponds to the fuchsia.io [`fio::Flags`] type. See fuchsia.io's Open method for
60 /// more information regarding how flags are handled and what flag combinations are valid.
61 ///
62 /// If this method was initiated by a FIDL Open call, hierarchical rights are enforced at the
63 /// connection layer.
64 ///
65 /// If the implementation takes `object_request`, it is then responsible for sending an
66 /// `OnRepresentation` event when `flags` includes [`fio::Flags::FLAG_SEND_REPRESENTATION`].
67 ///
68 /// This method is called via either `Open` or `Reopen` fuchsia.io methods. Any errors returned
69 /// during this process will be sent via an epitaph on the `object_request` channel before
70 /// closing the channel.
71fn open(
72self: Arc<Self>,
73 scope: ExecutionScope,
74 path: Path,
75 flags: fio::Flags,
76 object_request: ObjectRequestRef<'_>,
77 ) -> Result<(), Status>;
7879/// Same as [`Self::open`] but the implementation is async. This may be more efficient if the
80 /// directory needs to do async work to open the connection.
81fn open_async(
82self: Arc<Self>,
83 scope: ExecutionScope,
84 path: Path,
85 flags: fio::Flags,
86 object_request: ObjectRequestRef<'_>,
87 ) -> impl Future<Output = Result<(), Status>> + Send
88where
89Self: Sized,
90 {
91 ready(self.open(scope, path, flags, object_request))
92 }
9394/// Reads directory entries starting from `pos` by adding them to `sink`.
95 /// Once finished, should return a sealed sink.
96// The lifetimes here are because of https://github.com/rust-lang/rust/issues/63033.
97fn read_dirents<'a>(
98&'a self,
99 pos: &'a TraversalPosition,
100 sink: Box<dyn dirents_sink::Sink>,
101 ) -> impl Future<Output = Result<(TraversalPosition, Box<dyn dirents_sink::Sealed>), Status>> + Send
102where
103Self: Sized;
104105/// Register a watcher for this directory.
106 /// Implementations will probably want to use a `Watcher` to manage watchers.
107fn register_watcher(
108self: Arc<Self>,
109 scope: ExecutionScope,
110 mask: fio::WatchMask,
111 watcher: DirectoryWatcher,
112 ) -> Result<(), Status>;
113114/// Unregister a watcher from this directory. The watcher should no longer
115 /// receive events.
116fn unregister_watcher(self: Arc<Self>, key: usize);
117118/// DEPRECATED - Do not implement unless required for backwards compatibility. Called when
119 /// handling a fuchsia.io/Directory.DeprecatedOpen request.
120fn deprecated_open(
121self: Arc<Self>,
122 _scope: ExecutionScope,
123 flags: fio::OpenFlags,
124 _path: Path,
125 server_end: ServerEnd<fio::NodeMarker>,
126 ) {
127 flags.to_object_request(server_end.into_channel()).shutdown(Status::NOT_SUPPORTED);
128 }
129}
130131/// This trait indicates a directory that can be mutated by adding and removing entries.
132/// This trait must be implemented to use a `MutableConnection`, however, a directory could also
133/// implement the `DirectlyMutable` type, which provides a blanket implementation of this trait.
134pub trait MutableDirectory: Directory + Send + Sync {
135/// Adds a child entry to this directory. If the target exists, it should fail with
136 /// ZX_ERR_ALREADY_EXISTS.
137fn link<'a>(
138self: Arc<Self>,
139 _name: String,
140 _source_dir: Arc<dyn Any + Send + Sync>,
141 _source_name: &'a str,
142 ) -> BoxFuture<'a, Result<(), Status>> {
143 Box::pin(ready(Err(Status::NOT_SUPPORTED)))
144 }
145146/// Set the mutable attributes of this directory based on the values in `attributes`. If the
147 /// directory does not support updating *all* of the specified attributes, implementations
148 /// should fail with `ZX_ERR_NOT_SUPPORTED`.
149fn update_attributes(
150&self,
151 attributes: fio::MutableNodeAttributes,
152 ) -> impl Future<Output = Result<(), Status>> + Send
153where
154Self: Sized;
155156/// Removes an entry from this directory.
157fn unlink(
158self: Arc<Self>,
159 name: &str,
160 must_be_directory: bool,
161 ) -> impl Future<Output = Result<(), Status>> + Send
162where
163Self: Sized;
164165/// Syncs the directory.
166fn sync(&self) -> impl Future<Output = Result<(), Status>> + Send
167where
168Self: Sized;
169170/// Renames into this directory.
171fn rename(
172self: Arc<Self>,
173 _src_dir: Arc<dyn MutableDirectory>,
174 _src_name: Path,
175 _dst_name: Path,
176 ) -> BoxFuture<'static, Result<(), Status>> {
177 Box::pin(ready(Err(Status::NOT_SUPPORTED)))
178 }
179180/// Creates a symbolic link.
181fn create_symlink(
182&self,
183 _name: String,
184 _target: Vec<u8>,
185 _connection: Option<ServerEnd<fio::SymlinkMarker>>,
186 ) -> impl Future<Output = Result<(), Status>> + Send
187where
188Self: Sized,
189 {
190 ready(Err(Status::NOT_SUPPORTED))
191 }
192193/// List extended attributes.
194fn list_extended_attributes(&self) -> impl Future<Output = Result<Vec<Vec<u8>>, Status>> + Send
195where
196Self: Sized,
197 {
198 ready(Err(Status::NOT_SUPPORTED))
199 }
200201/// Get the value for an extended attribute.
202fn get_extended_attribute(
203&self,
204 _name: Vec<u8>,
205 ) -> impl Future<Output = Result<Vec<u8>, Status>> + Send
206where
207Self: Sized,
208 {
209 ready(Err(Status::NOT_SUPPORTED))
210 }
211212/// Set the value for an extended attribute.
213fn set_extended_attribute(
214&self,
215 _name: Vec<u8>,
216 _value: Vec<u8>,
217 _mode: fio::SetExtendedAttributeMode,
218 ) -> impl Future<Output = Result<(), Status>> + Send
219where
220Self: Sized,
221 {
222 ready(Err(Status::NOT_SUPPORTED))
223 }
224225/// Remove the value for an extended attribute.
226fn remove_extended_attribute(
227&self,
228 _name: Vec<u8>,
229 ) -> impl Future<Output = Result<(), Status>> + Send
230where
231Self: Sized,
232 {
233 ready(Err(Status::NOT_SUPPORTED))
234 }
235}