Skip to main content

vfs/
remote.rs

1// Copyright 2021 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//! A node which forwards open requests to a remote fuchsia.io server.
6
7#[cfg(test)]
8mod tests;
9
10use crate::ObjectRequestRef;
11#[cfg(any(fuchsia_api_level_at_least = "PLATFORM", not(fuchsia_api_level_at_least = "NEXT")))]
12use crate::ToObjectRequest as _;
13use crate::directory::entry::{DirectoryEntry, EntryInfo, GetEntryInfo, OpenRequest};
14use crate::execution_scope::ExecutionScope;
15use crate::path::Path;
16#[cfg(any(fuchsia_api_level_at_least = "PLATFORM", not(fuchsia_api_level_at_least = "NEXT")))]
17use fidl::endpoints::ServerEnd;
18use fidl_fuchsia_io as fio;
19use std::sync::Arc;
20use zx_status::Status;
21
22pub trait RemoteLike {
23    /// Called when a fuchsia.io/Directory.Open request should be forwarded to the remote node.
24    fn open(
25        self: Arc<Self>,
26        scope: ExecutionScope,
27        path: Path,
28        flags: fio::Flags,
29        object_request: ObjectRequestRef<'_>,
30    ) -> Result<(), Status>;
31
32    /// Returns whether the remote should be opened lazily for the given path.  If true, the remote
33    /// won't be opened until the channel in the request is readable.  This request will *not* be
34    /// considered lazy if the request requires an event such as OnRepresentation, and this method
35    /// will by bypassed.
36    fn lazy(&self, _path: &Path) -> bool {
37        false
38    }
39
40    #[cfg(any(fuchsia_api_level_at_least = "PLATFORM", not(fuchsia_api_level_at_least = "NEXT")))]
41    /// DEPRECATED - Do not implement unless required for backwards compatibility. Called when
42    /// forwarding fuchsia.io/Directory.DeprecatedOpen requests.
43    fn deprecated_open(
44        self: Arc<Self>,
45        _scope: ExecutionScope,
46        flags: fio::OpenFlags,
47        _path: Path,
48        server_end: ServerEnd<fio::NodeMarker>,
49    ) {
50        flags.to_object_request(server_end.into_channel()).shutdown(Status::NOT_SUPPORTED);
51    }
52}
53
54/// Creates a new node that forwards open requests a remote directory server.
55pub fn remote_dir(dir: fio::DirectoryProxy) -> Arc<impl DirectoryEntry + RemoteLike> {
56    Arc::new(RemoteDir { dir })
57}
58
59/// [`RemoteDir`] implements [`RemoteLike`]` by forwarding open requests to a remote directory.
60struct RemoteDir {
61    dir: fio::DirectoryProxy,
62}
63
64impl GetRemoteDir for RemoteDir {
65    fn get_remote_dir(&self) -> Result<fio::DirectoryProxy, Status> {
66        Ok(Clone::clone(&self.dir))
67    }
68}
69
70/// A trait that can be implemented to return a directory proxy that should be used as a remote
71/// directory.
72pub trait GetRemoteDir {
73    fn get_remote_dir(&self) -> Result<fio::DirectoryProxy, Status>;
74}
75
76impl<T: GetRemoteDir + Send + Sync + 'static> GetEntryInfo for T {
77    fn entry_info(&self) -> EntryInfo {
78        EntryInfo::new(fio::INO_UNKNOWN, fio::DirentType::Directory)
79    }
80}
81
82impl<T: GetRemoteDir + Send + Sync + 'static> DirectoryEntry for T {
83    fn open_entry(self: Arc<Self>, request: OpenRequest<'_>) -> Result<(), Status> {
84        request.open_remote(self)
85    }
86}
87
88impl<T: GetRemoteDir> RemoteLike for T {
89    #[cfg(any(fuchsia_api_level_at_least = "PLATFORM", not(fuchsia_api_level_at_least = "NEXT")))]
90    fn deprecated_open(
91        self: Arc<Self>,
92        _scope: ExecutionScope,
93        flags: fio::OpenFlags,
94        path: Path,
95        server_end: ServerEnd<fio::NodeMarker>,
96    ) {
97        flags.to_object_request(server_end).handle(|object_request| {
98            let _ = self.get_remote_dir()?.deprecated_open(
99                flags,
100                fio::ModeType::empty(),
101                path.as_ref(),
102                object_request.take().into_server_end(),
103            );
104            Ok(())
105        });
106    }
107
108    fn open(
109        self: Arc<Self>,
110        _scope: ExecutionScope,
111        path: Path,
112        flags: fio::Flags,
113        object_request: ObjectRequestRef<'_>,
114    ) -> Result<(), Status> {
115        // There is nowhere to propagate any errors since we take the `object_request`. This is okay
116        // as the channel will be dropped and closed if the wire call fails.
117        let _ = self.get_remote_dir()?.open(
118            path.as_ref(),
119            flags,
120            &object_request.options(),
121            object_request.take().into_channel(),
122        );
123        Ok(())
124    }
125}