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    fn open(
21        self: Arc<Self>,
22        scope: ExecutionScope,
23        flags: fio::OpenFlags,
24        path: Path,
25        server_end: ServerEnd<fio::NodeMarker>,
26    );
27
28    fn open3(
29        self: Arc<Self>,
30        scope: ExecutionScope,
31        path: Path,
32        flags: fio::Flags,
33        object_request: ObjectRequestRef<'_>,
34    ) -> Result<(), Status>;
35
36    /// Returns whether the remote should be opened lazily for the given path.  If true, the remote
37    /// won't be opened until the channel in the request is readable.  This request will *not* be
38    /// considered lazy if the request requires an event such as OnRepresentation, and this method
39    /// will by bypassed.
40    fn lazy(&self, _path: &Path) -> bool {
41        false
42    }
43}
44
45/// Create a new [`Remote`] node that forwards open requests to the provided [`DirectoryProxy`],
46/// effectively handing off the handling of any further requests to the remote fidl server.
47pub fn remote_dir(dir: fio::DirectoryProxy) -> Arc<impl DirectoryEntry + RemoteLike> {
48    Arc::new(RemoteDir { dir })
49}
50
51/// [`RemoteDir`] implements [`RemoteLike`]` which forwards open/open2 requests to a remote
52/// directory.
53struct RemoteDir {
54    dir: fio::DirectoryProxy,
55}
56
57impl GetRemoteDir for RemoteDir {
58    fn get_remote_dir(&self) -> Result<fio::DirectoryProxy, Status> {
59        Ok(Clone::clone(&self.dir))
60    }
61}
62
63/// A trait that can be implemented to return a directory proxy that should be used as a remote
64/// directory.
65pub trait GetRemoteDir {
66    fn get_remote_dir(&self) -> Result<fio::DirectoryProxy, Status>;
67}
68
69impl<T: GetRemoteDir + Send + Sync + 'static> GetEntryInfo for T {
70    fn entry_info(&self) -> EntryInfo {
71        EntryInfo::new(fio::INO_UNKNOWN, fio::DirentType::Directory)
72    }
73}
74
75impl<T: GetRemoteDir + Send + Sync + 'static> DirectoryEntry for T {
76    fn open_entry(self: Arc<Self>, request: OpenRequest<'_>) -> Result<(), Status> {
77        request.open_remote(self)
78    }
79}
80
81impl<T: GetRemoteDir> RemoteLike for T {
82    fn open(
83        self: Arc<Self>,
84        _scope: ExecutionScope,
85        flags: fio::OpenFlags,
86        path: Path,
87        server_end: ServerEnd<fio::NodeMarker>,
88    ) {
89        flags.to_object_request(server_end).handle(|object_request| {
90            #[cfg(fuchsia_api_level_at_least = "NEXT")]
91            let _ = self.get_remote_dir()?.deprecated_open(
92                flags,
93                fio::ModeType::empty(),
94                path.as_ref(),
95                object_request.take().into_server_end(),
96            );
97            #[cfg(not(fuchsia_api_level_at_least = "NEXT"))]
98            let _ = self.get_remote_dir()?.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 open3(
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        #[cfg(fuchsia_api_level_at_least = "NEXT")]
118        let _ = self.get_remote_dir()?.open(
119            path.as_ref(),
120            flags,
121            &object_request.options(),
122            object_request.take().into_channel(),
123        );
124        #[cfg(not(fuchsia_api_level_at_least = "NEXT"))]
125        let _ = self.get_remote_dir()?.open3(
126            path.as_ref(),
127            flags,
128            &object_request.options(),
129            object_request.take().into_channel(),
130        );
131        Ok(())
132    }
133}