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::{ready, Future};
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 TryFrom<fidl::endpoints::ServerEnd<fio::DirectoryWatcherMarker>> for DirectoryWatcher {
40        type Error = zx_status::Status;
41
42        fn try_from(
43            server_end: fidl::endpoints::ServerEnd<fio::DirectoryWatcherMarker>,
44        ) -> Result<Self, Self::Error> {
45            let channel = fuchsia_async::Channel::from_channel(server_end.into_channel());
46            Ok(Self { channel })
47        }
48    }
49}
50
51pub use private::DirectoryWatcher;
52
53/// 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.
71    fn open(
72        self: Arc<Self>,
73        scope: ExecutionScope,
74        path: Path,
75        flags: fio::Flags,
76        object_request: ObjectRequestRef<'_>,
77    ) -> Result<(), Status>;
78
79    /// 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.
81    fn open_async(
82        self: Arc<Self>,
83        scope: ExecutionScope,
84        path: Path,
85        flags: fio::Flags,
86        object_request: ObjectRequestRef<'_>,
87    ) -> impl Future<Output = Result<(), Status>> + Send
88    where
89        Self: Sized,
90    {
91        ready(self.open(scope, path, flags, object_request))
92    }
93
94    /// 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.
97    fn 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
102    where
103        Self: Sized;
104
105    /// Register a watcher for this directory.
106    /// Implementations will probably want to use a `Watcher` to manage watchers.
107    fn register_watcher(
108        self: Arc<Self>,
109        scope: ExecutionScope,
110        mask: fio::WatchMask,
111        watcher: DirectoryWatcher,
112    ) -> Result<(), Status>;
113
114    /// Unregister a watcher from this directory. The watcher should no longer
115    /// receive events.
116    fn unregister_watcher(self: Arc<Self>, key: usize);
117
118    /// DEPRECATED - Do not implement unless required for backwards compatibility. Called when
119    /// handling a fuchsia.io/Directory.DeprecatedOpen request.
120    fn deprecated_open(
121        self: 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}
130
131/// 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.
137    fn link<'a>(
138        self: 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    }
145
146    /// 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`.
149    fn update_attributes(
150        &self,
151        attributes: fio::MutableNodeAttributes,
152    ) -> impl Future<Output = Result<(), Status>> + Send
153    where
154        Self: Sized;
155
156    /// Removes an entry from this directory.
157    fn unlink(
158        self: Arc<Self>,
159        name: &str,
160        must_be_directory: bool,
161    ) -> impl Future<Output = Result<(), Status>> + Send
162    where
163        Self: Sized;
164
165    /// Syncs the directory.
166    fn sync(&self) -> impl Future<Output = Result<(), Status>> + Send
167    where
168        Self: Sized;
169
170    /// Renames into this directory.
171    fn rename(
172        self: 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    }
179
180    /// Creates a symbolic link.
181    fn create_symlink(
182        &self,
183        _name: String,
184        _target: Vec<u8>,
185        _connection: Option<ServerEnd<fio::SymlinkMarker>>,
186    ) -> impl Future<Output = Result<(), Status>> + Send
187    where
188        Self: Sized,
189    {
190        ready(Err(Status::NOT_SUPPORTED))
191    }
192
193    /// List extended attributes.
194    fn list_extended_attributes(&self) -> impl Future<Output = Result<Vec<Vec<u8>>, Status>> + Send
195    where
196        Self: Sized,
197    {
198        ready(Err(Status::NOT_SUPPORTED))
199    }
200
201    /// Get the value for an extended attribute.
202    fn get_extended_attribute(
203        &self,
204        _name: Vec<u8>,
205    ) -> impl Future<Output = Result<Vec<u8>, Status>> + Send
206    where
207        Self: Sized,
208    {
209        ready(Err(Status::NOT_SUPPORTED))
210    }
211
212    /// Set the value for an extended attribute.
213    fn set_extended_attribute(
214        &self,
215        _name: Vec<u8>,
216        _value: Vec<u8>,
217        _mode: fio::SetExtendedAttributeMode,
218    ) -> impl Future<Output = Result<(), Status>> + Send
219    where
220        Self: Sized,
221    {
222        ready(Err(Status::NOT_SUPPORTED))
223    }
224
225    /// Remove the value for an extended attribute.
226    fn remove_extended_attribute(
227        &self,
228        _name: Vec<u8>,
229    ) -> impl Future<Output = Result<(), Status>> + Send
230    where
231        Self: Sized,
232    {
233        ready(Err(Status::NOT_SUPPORTED))
234    }
235}