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 fn read_dirents(
93 &self,
94 pos: &TraversalPosition,
95 sink: Box<dyn dirents_sink::Sink>,
96 ) -> impl Future<Output = Result<(TraversalPosition, Box<dyn dirents_sink::Sealed>), Status>> + Send
97 where
98 Self: Sized;
99
100 /// Register a watcher for this directory.
101 /// Implementations will probably want to use a `Watcher` to manage watchers.
102 fn register_watcher(
103 self: Arc<Self>,
104 scope: ExecutionScope,
105 mask: fio::WatchMask,
106 watcher: DirectoryWatcher,
107 ) -> Result<(), Status>;
108
109 /// Unregister a watcher from this directory. The watcher should no longer
110 /// receive events.
111 fn unregister_watcher(self: Arc<Self>, key: usize);
112
113 /// DEPRECATED - Do not implement unless required for backwards compatibility. Called when
114 /// handling a fuchsia.io/Directory.DeprecatedOpen request.
115 fn deprecated_open(
116 self: Arc<Self>,
117 _scope: ExecutionScope,
118 flags: fio::OpenFlags,
119 _path: Path,
120 server_end: ServerEnd<fio::NodeMarker>,
121 ) {
122 flags.to_object_request(server_end.into_channel()).shutdown(Status::NOT_SUPPORTED);
123 }
124}
125
126/// This trait indicates a directory that can be mutated by adding and removing entries.
127/// This trait must be implemented to use a `MutableConnection`, however, a directory could also
128/// implement the `DirectlyMutable` type, which provides a blanket implementation of this trait.
129pub trait MutableDirectory: Directory + Send + Sync {
130 /// Adds a child entry to this directory. If the target exists, it should fail with
131 /// ZX_ERR_ALREADY_EXISTS.
132 fn link<'a>(
133 self: Arc<Self>,
134 _name: String,
135 _source_dir: Arc<dyn Any + Send + Sync>,
136 _source_name: &'a str,
137 ) -> BoxFuture<'a, Result<(), Status>> {
138 Box::pin(ready(Err(Status::NOT_SUPPORTED)))
139 }
140
141 /// Set the mutable attributes of this directory based on the values in `attributes`. If the
142 /// directory does not support updating *all* of the specified attributes, implementations
143 /// should fail with `ZX_ERR_NOT_SUPPORTED`.
144 fn update_attributes(
145 &self,
146 attributes: fio::MutableNodeAttributes,
147 ) -> impl Future<Output = Result<(), Status>> + Send
148 where
149 Self: Sized;
150
151 /// Removes an entry from this directory.
152 fn unlink(
153 self: Arc<Self>,
154 name: &str,
155 must_be_directory: bool,
156 ) -> impl Future<Output = Result<(), Status>> + Send
157 where
158 Self: Sized;
159
160 /// Syncs the directory.
161 fn sync(&self) -> impl Future<Output = Result<(), Status>> + Send
162 where
163 Self: Sized;
164
165 /// Renames into this directory.
166 fn rename(
167 self: Arc<Self>,
168 _src_dir: Arc<dyn MutableDirectory>,
169 _src_name: Path,
170 _dst_name: Path,
171 ) -> BoxFuture<'static, Result<(), Status>> {
172 Box::pin(ready(Err(Status::NOT_SUPPORTED)))
173 }
174
175 /// Creates a symbolic link.
176 fn create_symlink(
177 &self,
178 _name: String,
179 _target: Vec<u8>,
180 _connection: Option<ServerEnd<fio::SymlinkMarker>>,
181 ) -> impl Future<Output = Result<(), Status>> + Send
182 where
183 Self: Sized,
184 {
185 ready(Err(Status::NOT_SUPPORTED))
186 }
187}