Skip to main content

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