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