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;
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 this
57 /// one otherwise. `path` will not contain any "." or ".." components.
58 ///
59 /// `flags` holds one or more of the `OPEN_RIGHT_*`, `OPEN_FLAG_*` constants. Processing of the
60 /// `flags` value is specific to the item - in particular, the `OPEN_RIGHT_*` flags need to
61 /// match the item capabilities.
62 ///
63 /// It is the responsibility of the implementation to strip POSIX flags if the path crosses
64 /// a boundary that does not have the required permissions.
65 ///
66 /// It is the responsibility of the implementation to send an `OnOpen` event on the channel
67 /// contained by `server_end` in case [`fio::OpenFlags::DESCRIBE`]` was set.
68 ///
69 /// This method is called via either `Open` or `Clone` fuchsia.io methods. Any errors that occur
70 /// during this process should be sent as a channel closure epitaph via `server_end`. No errors
71 /// should ever affect the connection where `Open` or `Clone` were received.
72 fn open(
73 self: Arc<Self>,
74 scope: ExecutionScope,
75 flags: fio::OpenFlags,
76 path: Path,
77 server_end: ServerEnd<fio::NodeMarker>,
78 );
79
80 /// Opens a connection to this item if the `path` is "." or a connection to an item inside
81 /// this one otherwise. `path` will not contain any "." or ".." components.
82 ///
83 /// `flags` corresponds to the fuchsia.io [`fio::Flags`] type. See fuchsia.io's Open3 method for
84 /// more information regarding how flags are handled and what flag combinations are valid.
85 ///
86 /// If this method was initiated by a FIDL Open3 call, hierarchical rights are enforced at the
87 /// connection layer.
88 ///
89 /// If the implementation takes `object_request`, it is then responsible for sending an
90 /// `OnRepresentation` event when `flags` includes [`fio::Flags::FLAG_SEND_REPRESENTATION`].
91 ///
92 /// This method is called via either `Open3` or `Reopen` fuchsia.io methods. Any errors returned
93 /// during this process will be sent via an epitaph on the `object_request` channel before
94 /// closing the channel.
95 fn open3(
96 self: Arc<Self>,
97 scope: ExecutionScope,
98 path: Path,
99 flags: fio::Flags,
100 object_request: ObjectRequestRef<'_>,
101 ) -> Result<(), Status>;
102
103 /// Same as `open3` but the implementation is async. This may be more efficient if the directory
104 /// needs to do async work to open the connection.
105 fn open3_async(
106 self: Arc<Self>,
107 scope: ExecutionScope,
108 path: Path,
109 flags: fio::Flags,
110 object_request: ObjectRequestRef<'_>,
111 ) -> impl Future<Output = Result<(), Status>> + Send
112 where
113 Self: Sized,
114 {
115 ready(self.open3(scope, path, flags, object_request))
116 }
117
118 /// Reads directory entries starting from `pos` by adding them to `sink`.
119 /// Once finished, should return a sealed sink.
120 // The lifetimes here are because of https://github.com/rust-lang/rust/issues/63033.
121 fn read_dirents<'a>(
122 &'a self,
123 pos: &'a TraversalPosition,
124 sink: Box<dyn dirents_sink::Sink>,
125 ) -> impl Future<Output = Result<(TraversalPosition, Box<dyn dirents_sink::Sealed>), Status>> + Send
126 where
127 Self: Sized;
128
129 /// Register a watcher for this directory.
130 /// Implementations will probably want to use a `Watcher` to manage watchers.
131 fn register_watcher(
132 self: Arc<Self>,
133 scope: ExecutionScope,
134 mask: fio::WatchMask,
135 watcher: DirectoryWatcher,
136 ) -> Result<(), Status>;
137
138 /// Unregister a watcher from this directory. The watcher should no longer
139 /// receive events.
140 fn unregister_watcher(self: Arc<Self>, key: usize);
141}
142
143/// This trait indicates a directory that can be mutated by adding and removing entries.
144/// This trait must be implemented to use a `MutableConnection`, however, a directory could also
145/// implement the `DirectlyMutable` type, which provides a blanket implementation of this trait.
146pub trait MutableDirectory: Directory + Send + Sync {
147 /// Adds a child entry to this directory. If the target exists, it should fail with
148 /// ZX_ERR_ALREADY_EXISTS.
149 fn link<'a>(
150 self: Arc<Self>,
151 _name: String,
152 _source_dir: Arc<dyn Any + Send + Sync>,
153 _source_name: &'a str,
154 ) -> BoxFuture<'a, Result<(), Status>> {
155 Box::pin(ready(Err(Status::NOT_SUPPORTED)))
156 }
157
158 /// Set the mutable attributes of this directory based on the values in `attributes`. If the
159 /// directory does not support updating *all* of the specified attributes, implementations
160 /// should fail with `ZX_ERR_NOT_SUPPORTED`.
161 fn update_attributes(
162 &self,
163 attributes: fio::MutableNodeAttributes,
164 ) -> impl Future<Output = Result<(), Status>> + Send
165 where
166 Self: Sized;
167
168 /// Removes an entry from this directory.
169 fn unlink(
170 self: Arc<Self>,
171 name: &str,
172 must_be_directory: bool,
173 ) -> impl Future<Output = Result<(), Status>> + Send
174 where
175 Self: Sized;
176
177 /// Syncs the directory.
178 fn sync(&self) -> impl Future<Output = Result<(), Status>> + Send
179 where
180 Self: Sized;
181
182 /// Renames into this directory.
183 fn rename(
184 self: Arc<Self>,
185 _src_dir: Arc<dyn MutableDirectory>,
186 _src_name: Path,
187 _dst_name: Path,
188 ) -> BoxFuture<'static, Result<(), Status>> {
189 Box::pin(ready(Err(Status::NOT_SUPPORTED)))
190 }
191
192 /// Creates a symbolic link.
193 fn create_symlink(
194 &self,
195 _name: String,
196 _target: Vec<u8>,
197 _connection: Option<ServerEnd<fio::SymlinkMarker>>,
198 ) -> impl Future<Output = Result<(), Status>> + Send
199 where
200 Self: Sized,
201 {
202 ready(Err(Status::NOT_SUPPORTED))
203 }
204
205 /// List extended attributes.
206 fn list_extended_attributes(&self) -> impl Future<Output = Result<Vec<Vec<u8>>, Status>> + Send
207 where
208 Self: Sized,
209 {
210 ready(Err(Status::NOT_SUPPORTED))
211 }
212
213 /// Get the value for an extended attribute.
214 fn get_extended_attribute(
215 &self,
216 _name: Vec<u8>,
217 ) -> impl Future<Output = Result<Vec<u8>, Status>> + Send
218 where
219 Self: Sized,
220 {
221 ready(Err(Status::NOT_SUPPORTED))
222 }
223
224 /// Set the value for an extended attribute.
225 fn set_extended_attribute(
226 &self,
227 _name: Vec<u8>,
228 _value: Vec<u8>,
229 _mode: fio::SetExtendedAttributeMode,
230 ) -> impl Future<Output = Result<(), Status>> + Send
231 where
232 Self: Sized,
233 {
234 ready(Err(Status::NOT_SUPPORTED))
235 }
236
237 /// Remove the value for an extended attribute.
238 fn remove_extended_attribute(
239 &self,
240 _name: Vec<u8>,
241 ) -> impl Future<Output = Result<(), Status>> + Send
242 where
243 Self: Sized,
244 {
245 ready(Err(Status::NOT_SUPPORTED))
246 }
247}