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, true, false, false)
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, readable: bool, writable: bool, executable: bool) -> Arc<Self> {
69 assert!(readable, "VmoFile must be readable");
71 assert!(!writable, "VmoFile no longer supports writing");
72 Self::new_with_inode(vmo, readable, writable, executable, fio::INO_UNKNOWN)
73 }
74
75 pub fn new_with_inode(
85 vmo: zx::Vmo,
86 readable: bool,
87 writable: bool,
88 executable: bool,
89 inode: u64,
90 ) -> Arc<Self> {
91 assert!(readable, "VmoFile must be readable");
93 assert!(!writable, "VmoFile no longer supports writing");
94 Arc::new(VmoFile { executable, inode, vmo })
95 }
96}
97
98impl FileLike for VmoFile {
99 fn open(
100 self: Arc<Self>,
101 scope: ExecutionScope,
102 options: FileOptions,
103 object_request: ObjectRequestRef<'_>,
104 ) -> Result<(), Status> {
105 StreamIoConnection::create_sync(scope, self, options, object_request.take());
106 Ok(())
107 }
108}
109
110impl GetEntryInfo for VmoFile {
111 fn entry_info(&self) -> EntryInfo {
112 EntryInfo::new(self.inode, fio::DirentType::File)
113 }
114}
115
116impl DirectoryEntry for VmoFile {
117 fn open_entry(self: Arc<Self>, request: OpenRequest<'_>) -> Result<(), Status> {
118 request.open_file(self)
119 }
120}
121
122impl Node for VmoFile {
123 async fn get_attributes(
124 &self,
125 requested_attributes: fio::NodeAttributesQuery,
126 ) -> Result<fio::NodeAttributes2, Status> {
127 let content_size = if requested_attributes.intersects(
128 fio::NodeAttributesQuery::CONTENT_SIZE.union(fio::NodeAttributesQuery::STORAGE_SIZE),
129 ) {
130 Some(self.vmo.get_content_size()?)
131 } else {
132 None
133 };
134 let mut abilities = fio::Operations::GET_ATTRIBUTES | fio::Operations::READ_BYTES;
135 if self.executable {
136 abilities |= fio::Operations::EXECUTE
137 }
138 Ok(immutable_attributes!(
139 requested_attributes,
140 Immutable {
141 protocols: fio::NodeProtocolKinds::FILE,
142 abilities: abilities,
143 content_size: content_size,
144 storage_size: content_size,
145 id: self.inode,
146 }
147 ))
148 }
149}
150
151impl GetVmo for VmoFile {
153 fn get_vmo(&self) -> &zx::Vmo {
154 &self.vmo
155 }
156}
157
158impl File for VmoFile {
159 fn readable(&self) -> bool {
160 true
161 }
162
163 fn writable(&self) -> bool {
164 false
165 }
166
167 fn executable(&self) -> bool {
168 self.executable
169 }
170
171 async fn open_file(&self, _options: &FileOptions) -> Result<(), Status> {
172 Ok(())
173 }
174
175 async fn truncate(&self, _length: u64) -> Result<(), Status> {
176 Err(Status::NOT_SUPPORTED)
177 }
178
179 async fn get_backing_memory(&self, flags: fio::VmoFlags) -> Result<zx::Vmo, Status> {
180 let vmo_rights = vmo_flags_to_rights(flags)
184 | zx::Rights::BASIC
185 | zx::Rights::MAP
186 | zx::Rights::GET_PROPERTY;
187 if flags.contains(fio::VmoFlags::PRIVATE_CLONE) {
189 get_as_private(&self.vmo, vmo_rights)
190 } else {
191 self.vmo.duplicate_handle(vmo_rights)
192 }
193 }
194
195 async fn get_size(&self) -> Result<u64, Status> {
196 Ok(self.vmo.get_content_size()?)
197 }
198
199 async fn update_attributes(
200 &self,
201 _attributes: fio::MutableNodeAttributes,
202 ) -> Result<(), Status> {
203 Err(Status::NOT_SUPPORTED)
204 }
205
206 async fn sync(&self, _mode: SyncMode) -> Result<(), Status> {
207 Ok(())
208 }
209}
210
211fn get_as_private(vmo: &zx::Vmo, mut rights: zx::Rights) -> Result<zx::Vmo, zx::Status> {
212 const CHILD_OPTIONS: zx::VmoChildOptions =
215 zx::VmoChildOptions::SNAPSHOT_AT_LEAST_ON_WRITE.union(zx::VmoChildOptions::NO_WRITE);
216
217 rights |= zx::Rights::SET_PROPERTY;
219
220 let size = vmo.get_content_size()?;
221 let new_vmo = vmo.create_child(CHILD_OPTIONS, 0, size)?;
222 new_vmo.replace_handle(rights)
223}