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