fuchsia_component_directory/
lib.rs1#![deny(missing_docs)]
11
12use anyhow::{Context, Error};
13use fidl::endpoints::ClientEnd;
14use fidl_fuchsia_io as fio;
15use std::sync::Arc;
16
17pub trait Directory {
19 fn open(&self, path: &str, flags: fio::Flags, server_end: zx::Channel) -> Result<(), Error>;
21}
22
23impl Directory for fio::DirectoryProxy {
24 fn open(&self, path: &str, flags: fio::Flags, server_end: zx::Channel) -> Result<(), Error> {
25 #[cfg(fuchsia_api_level_at_least = "27")]
26 let () = self.open(path, flags, &fio::Options::default(), server_end.into())?;
27 #[cfg(not(fuchsia_api_level_at_least = "27"))]
28 let () = self.open3(path, flags, &fio::Options::default(), server_end.into())?;
29 Ok(())
30 }
31}
32
33impl Directory for fio::DirectorySynchronousProxy {
34 fn open(&self, path: &str, flags: fio::Flags, server_end: zx::Channel) -> Result<(), Error> {
35 #[cfg(fuchsia_api_level_at_least = "27")]
36 let () = self.open(path, flags, &fio::Options::default(), server_end.into())?;
37 #[cfg(not(fuchsia_api_level_at_least = "27"))]
38 let () = self.open3(path, flags, &fio::Options::default(), server_end.into())?;
39 Ok(())
40 }
41}
42
43impl Directory for ClientEnd<fio::DirectoryMarker> {
44 fn open(&self, path: &str, flags: fio::Flags, server_end: zx::Channel) -> Result<(), Error> {
45 let raw_handle = self.channel().as_handle_ref().raw_handle();
46 unsafe {
48 let borrowed: zx::Channel = zx::NullableHandle::from_raw(raw_handle).into();
49 let proxy = fio::DirectorySynchronousProxy::new(borrowed);
50 #[cfg(fuchsia_api_level_at_least = "27")]
51 let res = proxy.open(path, flags, &fio::Options::default(), server_end.into());
52 #[cfg(not(fuchsia_api_level_at_least = "27"))]
53 let res = proxy.open3(path, flags, &fio::Options::default(), server_end.into());
54 std::mem::forget(proxy.into_channel());
55 res?;
56 }
57 Ok(())
58 }
59}
60
61pub trait AsRefDirectory {
67 fn as_ref_directory(&self) -> &dyn Directory;
69}
70
71impl AsRefDirectory for fio::DirectoryProxy {
72 fn as_ref_directory(&self) -> &dyn Directory {
73 self
74 }
75}
76
77impl AsRefDirectory for fio::DirectorySynchronousProxy {
78 fn as_ref_directory(&self) -> &dyn Directory {
79 self
80 }
81}
82
83impl AsRefDirectory for ClientEnd<fio::DirectoryMarker> {
84 fn as_ref_directory(&self) -> &dyn Directory {
85 self
86 }
87}
88
89impl<T: Directory> AsRefDirectory for Box<T> {
90 fn as_ref_directory(&self) -> &dyn Directory {
91 &**self
92 }
93}
94
95impl<T: Directory> AsRefDirectory for Arc<T> {
96 fn as_ref_directory(&self) -> &dyn Directory {
97 &**self
98 }
99}
100
101impl<T: Directory> AsRefDirectory for &T {
102 fn as_ref_directory(&self) -> &dyn Directory {
103 *self
104 }
105}
106
107pub fn open_directory_async(
109 parent: &impl AsRefDirectory,
110 path: &str,
111 rights: fio::Rights,
112) -> Result<fio::DirectoryProxy, Error> {
113 let (dir, server_end) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
114
115 let flags = fio::Flags::PROTOCOL_DIRECTORY | fio::Flags::from_bits_truncate(rights.bits());
116 let () = parent
117 .as_ref_directory()
118 .open(path, flags, server_end.into_channel())
119 .context("opening directory without describe")?;
120
121 Ok(dir)
122}
123
124pub fn open_file_async(
126 parent: &impl AsRefDirectory,
127 path: &str,
128 rights: fio::Rights,
129) -> Result<fio::FileProxy, Error> {
130 let (file, server_end) = fidl::endpoints::create_proxy::<fio::FileMarker>();
131
132 let flags = fio::Flags::PROTOCOL_FILE | fio::Flags::from_bits_truncate(rights.bits());
133 let () = parent
134 .as_ref_directory()
135 .open(path, flags, server_end.into_channel())
136 .context("opening file without describe")?;
137
138 Ok(file)
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144 use assert_matches::assert_matches;
145 use fuchsia_async as fasync;
146 use vfs::directory::immutable::simple;
147 use vfs::execution_scope::ExecutionScope;
148 use vfs::file::vmo::read_only;
149 use vfs::pseudo_directory;
150
151 #[fasync::run_singlethreaded(test)]
152 async fn open_directory_async_real() {
153 let dir = pseudo_directory! {
154 "dir" => simple(),
155 };
156 let dir = vfs::directory::serve_read_only(dir, ExecutionScope::new());
157 let dir = open_directory_async(&dir, "dir", fio::Rights::empty()).unwrap();
158 fuchsia_fs::directory::close(dir).await.unwrap();
159 }
160
161 #[fasync::run_singlethreaded(test)]
162 async fn open_directory_async_fake() {
163 let dir = pseudo_directory! {
164 "dir" => simple(),
165 };
166 let dir = vfs::directory::serve_read_only(dir, ExecutionScope::new());
167 let dir = open_directory_async(&dir, "fake", fio::Rights::empty()).unwrap();
168 assert_matches!(fuchsia_fs::directory::close(dir).await, Err(_));
170 }
171
172 #[fasync::run_singlethreaded(test)]
173 async fn open_file_async_real() {
174 let dir = pseudo_directory! {
175 "file" => read_only("read_only"),
176 };
177 let dir = vfs::directory::serve_read_only(dir, ExecutionScope::new());
178 let file = open_file_async(&dir, "file", fio::Rights::READ_BYTES).unwrap();
179 fuchsia_fs::file::close(file).await.unwrap();
180 }
181
182 #[fasync::run_singlethreaded(test)]
183 async fn open_file_async_fake() {
184 let dir = pseudo_directory! {
185 "file" => read_only("read_only"),
186 };
187 let dir = vfs::directory::serve_read_only(dir, ExecutionScope::new());
188 let fake = open_file_async(&dir, "fake", fio::Rights::READ_BYTES).unwrap();
189 assert_matches!(fuchsia_fs::file::close(fake).await, Err(_));
191 }
192}