sandbox/fidl/
dir_connector.rs

1// Copyright 2024 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
5use crate::dir_connector::DirConnectable;
6use crate::fidl::registry;
7use crate::{ConversionError, DirConnector, DirReceiver};
8use cm_types::{Name, RelativePath};
9use fidl::endpoints::{ClientEnd, ServerEnd};
10use futures::channel::mpsc;
11use std::fmt;
12use std::sync::Arc;
13use vfs::directory::entry::{DirectoryEntry, EntryInfo, GetEntryInfo, OpenRequest};
14use vfs::execution_scope::ExecutionScope;
15use vfs::object_request::{ObjectRequest, ObjectRequestRef};
16use vfs::remote::RemoteLike;
17use {fidl_fuchsia_component_sandbox as fsandbox, fidl_fuchsia_io as fio, fuchsia_async as fasync};
18
19impl DirConnector {
20    pub(crate) fn new_with_fidl_receiver(
21        receiver_client: ClientEnd<fsandbox::DirReceiverMarker>,
22        scope: &fasync::Scope,
23    ) -> Self {
24        let (sender, receiver) = mpsc::unbounded();
25        let receiver = DirReceiver::new(receiver);
26        // Exits when ServerEnd<DirReceiver> is closed
27        scope.spawn(receiver.handle_receiver(receiver_client.into_proxy()));
28        Self::new_sendable(sender)
29    }
30
31    pub fn from_directory_entry(
32        directory_entry: Arc<dyn DirectoryEntry>,
33        flags: fio::Flags,
34    ) -> Self {
35        assert_eq!(directory_entry.entry_info().type_(), fio::DirentType::Directory);
36        DirConnector::new_sendable(DirectoryEntryDirConnector {
37            directory_entry,
38            scope: ExecutionScope::new(),
39            flags,
40        })
41    }
42}
43
44struct DirectoryEntryDirConnector {
45    directory_entry: Arc<dyn DirectoryEntry>,
46    scope: ExecutionScope,
47    flags: fio::Flags,
48}
49
50// We can't derive Debug on DirectoryEntryDirConnector because of `Arc<dyn DirectoryEntry>`
51impl fmt::Debug for DirectoryEntryDirConnector {
52    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
53        #[allow(dead_code)]
54        #[derive(Debug)]
55        struct DirectoryEntryDirConnector<'a> {
56            scope: &'a ExecutionScope,
57            flags: &'a fio::Flags,
58        }
59        fmt::Debug::fmt(&DirectoryEntryDirConnector { scope: &self.scope, flags: &self.flags }, f)
60    }
61}
62
63impl DirConnectable for DirectoryEntryDirConnector {
64    fn maximum_flags(&self) -> fio::Flags {
65        self.flags
66    }
67
68    fn send(
69        &self,
70        channel: ServerEnd<fio::DirectoryMarker>,
71        subdir: RelativePath,
72        flags: Option<fio::Flags>,
73    ) -> Result<(), ()> {
74        let flags = flags.unwrap_or(self.flags);
75        let mut object_request =
76            ObjectRequest::new(flags, &fio::Options::default(), channel.into_channel());
77        let path = vfs::path::Path::validate_and_split(format!("{}", subdir))
78            .expect("relative path is invalid vfs path");
79        let open_request = OpenRequest::new(self.scope.clone(), flags, path, &mut object_request);
80        self.directory_entry.clone().open_entry(open_request).map_err(|_| ())
81    }
82}
83
84impl RemoteLike for DirConnector {
85    fn open(
86        self: Arc<Self>,
87        _scope: ExecutionScope,
88        mut path: vfs::path::Path,
89        flags: fio::Flags,
90        object_request: ObjectRequestRef<'_>,
91    ) -> Result<(), zx::Status> {
92        let mut relative_path = RelativePath::dot();
93        while let Some(segment) = path.next() {
94            let name = Name::new(segment).map_err(|_e|
95                // The VFS path isn't valid according to RelativePath.
96                zx::Status::INVALID_ARGS)?;
97            let success = relative_path.push(name);
98            if !success {
99                // The path is too long
100                return Err(zx::Status::INVALID_ARGS);
101            }
102        }
103        self.send(object_request.take().into_server_end(), relative_path, Some(flags))
104            .map_err(|_| zx::Status::INTERNAL)
105    }
106}
107
108impl DirectoryEntry for DirConnector {
109    fn open_entry(self: Arc<Self>, request: OpenRequest<'_>) -> Result<(), zx::Status> {
110        request.open_remote(self)
111    }
112}
113
114impl GetEntryInfo for DirConnector {
115    fn entry_info(&self) -> EntryInfo {
116        EntryInfo::new(fio::INO_UNKNOWN, fio::DirentType::Directory)
117    }
118}
119
120impl crate::RemotableCapability for DirConnector {
121    fn try_into_directory_entry(
122        self,
123        _scope: ExecutionScope,
124    ) -> Result<Arc<dyn DirectoryEntry>, ConversionError> {
125        Ok(Arc::new(self))
126    }
127}
128
129impl From<DirConnector> for fsandbox::DirConnector {
130    fn from(value: DirConnector) -> Self {
131        fsandbox::DirConnector { token: registry::insert_token(value.into()) }
132    }
133}
134
135impl From<DirConnector> for fsandbox::Capability {
136    fn from(connector: DirConnector) -> Self {
137        fsandbox::Capability::DirConnector(connector.into())
138    }
139}