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