virtual_file_system/
synchronous_file.rs1use core::{fmt::Debug, mem::forget};
2
3use crate::{Error, ItemStatic, Result, VirtualFileSystem};
4use alloc::{vec, vec::Vec};
5use exported_file_system::{ControlCommand, Permissions};
6use file_system::{
7 AccessFlags, AttributeFlags, Attributes, Context, Flags, Path, Position, Size, Statistics,
8};
9use shared::AnyByLayout;
10use task::TaskIdentifier;
11use task::block_on;
12use users::{GroupIdentifier, UserIdentifier};
13
14pub struct SynchronousFile {
15 pub(crate) item: ItemStatic,
16 pub(crate) position: Size,
17 pub(crate) flags: Flags,
18 pub(crate) context: Context,
19}
20
21impl Debug for SynchronousFile {
22 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
23 f.debug_struct("SynchronousFile")
24 .field("item", &self.item)
25 .field("position", &self.position)
26 .field("flags", &self.flags)
27 .finish()
28 }
29}
30
31impl SynchronousFile {
32 pub(crate) const fn new(
33 item: ItemStatic,
34 position: Size,
35 flags: Flags,
36 context: Context,
37 ) -> Self {
38 Self {
39 item,
40 position,
41 flags,
42 context,
43 }
44 }
45
46 pub fn open(
47 virtual_file_system: &VirtualFileSystem,
48 task: TaskIdentifier,
49 path: impl AsRef<Path>,
50 flags: Flags,
51 ) -> Result<Self> {
52 let file_identifier = block_on(virtual_file_system.open(&path, flags, task))?;
53
54 Ok(file_identifier.into_synchronous_file())
55 }
56
57 pub fn set_position(&mut self, position: &Position) -> Result<Size> {
58 self.position = self
59 .item
60 .as_base_operations()
61 .ok_or(Error::UnsupportedOperation)?
62 .set_position(&mut self.context, self.position, position)?;
63
64 Ok(self.position)
65 }
66
67 pub fn write(&mut self, buffer: &[u8]) -> Result<usize> {
70 if !self.flags.get_access().contains(AccessFlags::Write) {
71 return Err(Error::InvalidMode);
72 }
73
74 let size = self
75 .item
76 .as_base_operations()
77 .ok_or(Error::UnsupportedOperation)?
78 .write(&mut self.context, buffer, self.position)?;
79
80 self.position += size as Size;
81
82 Ok(size)
83 }
84
85 pub fn write_vectored(&mut self, buffers: &[&[u8]]) -> Result<usize> {
86 if !self.flags.get_access().contains(AccessFlags::Write) {
87 return Err(Error::InvalidMode);
88 }
89
90 let size = self
91 .item
92 .as_base_operations()
93 .ok_or(Error::UnsupportedOperation)?
94 .write_vectored(&mut self.context, buffers, self.position)?;
95
96 self.position += size as Size;
97
98 Ok(size)
99 }
100
101 pub fn write_line(&mut self, buffer: &[u8]) -> Result<usize> {
102 let size = self.write(buffer)? + self.write(b"\n")?;
103
104 Ok(size)
105 }
106
107 pub fn read(&mut self, buffer: &mut [u8]) -> Result<usize> {
108 let size = self
109 .item
110 .as_base_operations()
111 .ok_or(Error::UnsupportedOperation)?
112 .read(&mut self.context, buffer, self.position)?;
113
114 self.position += size as Size;
115
116 Ok(size)
117 }
118
119 pub fn read_until(&mut self, buffer: &mut [u8], delimiter: &[u8]) -> Result<usize> {
120 let size = self
121 .item
122 .as_base_operations()
123 .ok_or(Error::UnsupportedOperation)?
124 .read_until(&mut self.context, buffer, self.position, delimiter)?;
125
126 self.position += size as Size;
127
128 Ok(size)
129 }
130
131 pub fn read_to_end(&mut self, buffer: &mut Vec<u8>, chunk_size: usize) -> Result<usize> {
132 let mut total_read_size = 0;
133
134 let mut chunk = vec![0u8; chunk_size];
135 loop {
136 let read_size = self
137 .item
138 .as_base_operations()
139 .ok_or(Error::UnsupportedOperation)?
140 .read(&mut self.context, &mut chunk, self.position)?;
141
142 if read_size == 0 {
143 break;
144 }
145
146 self.position += read_size as Size;
147
148 total_read_size += read_size;
149
150 buffer.extend_from_slice(&chunk[..read_size]);
151
152 }
155
156 Ok(total_read_size)
157 }
158
159 pub fn flush(&mut self) -> Result<()> {
160 self.item
161 .as_base_operations()
162 .ok_or(Error::UnsupportedOperation)?
163 .flush(&mut self.context)?;
164
165 Ok(())
166 }
167
168 pub fn duplicate(&self) -> Result<Self> {
169 let context = self
170 .item
171 .as_base_operations()
172 .ok_or(Error::UnsupportedOperation)?
173 .clone_context(&self.context)?;
174
175 Ok(Self {
176 item: self.item.clone(),
177 position: self.position,
178 flags: self.flags,
179 context,
180 })
181 }
182
183 pub fn get_statistics(&mut self) -> Result<Statistics> {
184 let mut attributes = Attributes::new().set_mask(AttributeFlags::All);
185
186 self.item
187 .as_attributes_operations()
188 .ok_or(Error::UnsupportedOperation)?
189 .get_attributes(&mut self.context, &mut attributes)?;
190
191 Statistics::from_attributes(&attributes).ok_or(Error::MissingAttribute)
192 }
193
194 pub fn set_owner(
195 &mut self,
196 user: Option<UserIdentifier>,
197 group: Option<GroupIdentifier>,
198 ) -> Result<()> {
199 let mut attributes = Attributes::new();
200
201 if let Some(user) = user {
202 attributes = attributes.set_user(user);
203 }
204
205 if let Some(group) = group {
206 attributes = attributes.set_group(group);
207 }
208
209 self.item
210 .as_attributes_operations()
211 .ok_or(Error::UnsupportedOperation)?
212 .set_attributes(&mut self.context, &attributes)?;
213
214 Ok(())
215 }
216
217 pub fn set_permissions(&mut self, permissions: Permissions) -> Result<()> {
218 let attributes = Attributes::new().set_permissions(permissions);
219
220 self.item
221 .as_attributes_operations()
222 .ok_or(Error::UnsupportedOperation)?
223 .set_attributes(&mut self.context, &attributes)?;
224
225 Ok(())
226 }
227
228 pub fn control<C>(&mut self, _command: C, argument: &C::Input) -> Result<C::Output>
229 where
230 C: ControlCommand,
231 C::Output: Default,
232 {
233 let mut output = C::Output::default();
234
235 self.item
236 .as_base_operations()
237 .ok_or(Error::UnsupportedOperation)?
238 .control(
239 &mut self.context,
240 C::IDENTIFIER,
241 AnyByLayout::from(argument),
242 AnyByLayout::from_mutable(&mut output),
243 )?;
244
245 Ok(output)
246 }
247
248 pub fn get_access(&self) -> Result<AccessFlags> {
249 Ok(self.flags.get_access())
250 }
251
252 pub fn close_internal(&mut self, virtual_file_system: &VirtualFileSystem) -> crate::Result<()> {
253 block_on(virtual_file_system.close(&self.item, &mut self.context))
254 }
255
256 pub fn close(mut self, virtual_file_system: &VirtualFileSystem) -> crate::Result<()> {
257 let result = self.close_internal(virtual_file_system);
258 forget(self);
259
260 result
261 }
262}
263
264impl Drop for SynchronousFile {
265 fn drop(&mut self) {
266 let _ = self.close_internal(crate::get_instance()).map_err(|e| {
268 log::warning!("Failed to close SynchronousFile in Drop: {e}");
269 });
270 }
271}