vfs/directory/
entry_container.rs

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