1#[cfg(test)]
8mod tests;
9
10use crate::directory::entry::{DirectoryEntry, EntryInfo, GetEntryInfo, OpenRequest};
11use crate::execution_scope::ExecutionScope;
12use crate::file::common::vmo_flags_to_rights;
13use crate::file::{File, FileLike, FileOptions, GetVmo, StreamIoConnection, SyncMode};
14use crate::node::Node;
15use crate::ObjectRequestRef;
16use fidl_fuchsia_io as fio;
17use std::sync::Arc;
18use zx::{self as zx, HandleBased as _, Status, Vmo};
19
20pub fn read_only(content: impl AsRef<[u8]>) -> Arc<VmoFile> {
37 let bytes: &[u8] = content.as_ref();
38 let vmo = Vmo::create(bytes.len().try_into().unwrap()).unwrap();
39 if bytes.len() > 0 {
40 vmo.write(bytes, 0).unwrap();
41 }
42 VmoFile::new(vmo)
43}
44
45pub struct VmoFile {
47 executable: bool,
49
50 inode: u64,
52
53 vmo: Vmo,
55}
56
57unsafe impl Sync for VmoFile {}
58
59impl VmoFile {
60 pub fn new(vmo: zx::Vmo) -> Arc<Self> {
66 Self::new_with_inode(vmo, fio::INO_UNKNOWN)
67 }
68
69 pub fn new_with_inode(vmo: zx::Vmo, inode: u64) -> Arc<Self> {
76 Self::new_with_inode_and_executable(vmo, inode, false)
77 }
78
79 pub fn new_with_inode_and_executable(vmo: zx::Vmo, inode: u64, executable: bool) -> Arc<Self> {
87 Arc::new(VmoFile { executable, inode, vmo })
88 }
89}
90
91impl FileLike for VmoFile {
92 fn open(
93 self: Arc<Self>,
94 scope: ExecutionScope,
95 options: FileOptions,
96 object_request: ObjectRequestRef<'_>,
97 ) -> Result<(), Status> {
98 StreamIoConnection::create_sync(scope, self, options, object_request.take());
99 Ok(())
100 }
101}
102
103impl GetEntryInfo for VmoFile {
104 fn entry_info(&self) -> EntryInfo {
105 EntryInfo::new(self.inode, fio::DirentType::File)
106 }
107}
108
109impl DirectoryEntry for VmoFile {
110 fn open_entry(self: Arc<Self>, request: OpenRequest<'_>) -> Result<(), Status> {
111 request.open_file(self)
112 }
113}
114
115impl Node for VmoFile {
116 async fn get_attributes(
117 &self,
118 requested_attributes: fio::NodeAttributesQuery,
119 ) -> Result<fio::NodeAttributes2, Status> {
120 let content_size = if requested_attributes.intersects(
121 fio::NodeAttributesQuery::CONTENT_SIZE.union(fio::NodeAttributesQuery::STORAGE_SIZE),
122 ) {
123 Some(self.vmo.get_content_size()?)
124 } else {
125 None
126 };
127 let mut abilities = fio::Operations::GET_ATTRIBUTES | fio::Operations::READ_BYTES;
128 if self.executable {
129 abilities |= fio::Operations::EXECUTE
130 }
131 Ok(immutable_attributes!(
132 requested_attributes,
133 Immutable {
134 protocols: fio::NodeProtocolKinds::FILE,
135 abilities: abilities,
136 content_size: content_size,
137 storage_size: content_size,
138 id: self.inode,
139 }
140 ))
141 }
142}
143
144impl GetVmo for VmoFile {
146 fn get_vmo(&self) -> &zx::Vmo {
147 &self.vmo
148 }
149}
150
151impl File for VmoFile {
152 fn readable(&self) -> bool {
153 true
154 }
155
156 fn writable(&self) -> bool {
157 false
158 }
159
160 fn executable(&self) -> bool {
161 self.executable
162 }
163
164 async fn open_file(&self, _options: &FileOptions) -> Result<(), Status> {
165 Ok(())
166 }
167
168 async fn truncate(&self, _length: u64) -> Result<(), Status> {
169 Err(Status::NOT_SUPPORTED)
170 }
171
172 async fn get_backing_memory(&self, flags: fio::VmoFlags) -> Result<zx::Vmo, Status> {
173 let vmo_rights = vmo_flags_to_rights(flags)
177 | zx::Rights::BASIC
178 | zx::Rights::MAP
179 | zx::Rights::GET_PROPERTY;
180 if flags.contains(fio::VmoFlags::PRIVATE_CLONE) {
182 get_as_private(&self.vmo, vmo_rights)
183 } else {
184 self.vmo.duplicate_handle(vmo_rights)
185 }
186 }
187
188 async fn get_size(&self) -> Result<u64, Status> {
189 Ok(self.vmo.get_content_size()?)
190 }
191
192 async fn update_attributes(
193 &self,
194 _attributes: fio::MutableNodeAttributes,
195 ) -> Result<(), Status> {
196 Err(Status::NOT_SUPPORTED)
197 }
198
199 async fn sync(&self, _mode: SyncMode) -> Result<(), Status> {
200 Ok(())
201 }
202}
203
204fn get_as_private(vmo: &zx::Vmo, mut rights: zx::Rights) -> Result<zx::Vmo, zx::Status> {
205 const CHILD_OPTIONS: zx::VmoChildOptions =
208 zx::VmoChildOptions::SNAPSHOT_AT_LEAST_ON_WRITE.union(zx::VmoChildOptions::NO_WRITE);
209
210 rights |= zx::Rights::SET_PROPERTY;
212
213 let size = vmo.get_content_size()?;
214 let new_vmo = vmo.create_child(CHILD_OPTIONS, 0, size)?;
215 new_vmo.replace_handle(rights)
216}